package cn.kmsoft.gistool.gpkg;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;

import cn.kmsoft.common.ResInfo;
import cn.kmsoft.common.utils.FileUtil;
import cn.kmsoft.common.utils.JodaDateTimeUtil;
import cn.kmsoft.common.utils.StringUtil;
import cn.kmsoft.stgeometry.landm.FieldInfo;
import cn.kmsoft.stgeometry.util.CrsUtil;
import cn.kmsoft.stgeometry.util.JTSGeometryWKTUtil;
import cn.kmsoft.wololo.object.GeoJson;
import cn.kmsoft.wololo.object.GeoJsonFeature;
import cn.kmsoft.wololo.object.GeoJsonGeometry;
import org.geotools.data.FeatureWriter;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geojson.geom.GeometryJSON;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;

import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.joda.time.DateTime;

import com.alibaba.fastjson.JSONObject;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;

//import junit.framework.TestCase;
import mil.nga.geopackage.BoundingBox;
import mil.nga.geopackage.GeoPackage;
import mil.nga.geopackage.GeoPackageException;
import mil.nga.geopackage.attributes.AttributesColumn;
import mil.nga.geopackage.attributes.AttributesDao;
import mil.nga.geopackage.attributes.AttributesTable;

import mil.nga.geopackage.core.srs.SpatialReferenceSystem;
import mil.nga.geopackage.db.GeoPackageDataType;
import mil.nga.geopackage.features.columns.GeometryColumns;
import mil.nga.geopackage.features.user.FeatureColumn;
import mil.nga.geopackage.features.user.FeatureColumns;
import mil.nga.geopackage.features.user.FeatureDao;
import mil.nga.geopackage.features.user.FeatureResultSet;
import mil.nga.geopackage.features.user.FeatureRow;
import mil.nga.geopackage.features.user.FeatureTable;
import mil.nga.geopackage.geom.GeoPackageGeometryData;
import mil.nga.geopackage.manager.GeoPackageManager;
import mil.nga.geopackage.schema.TableColumnKey;
import mil.nga.geopackage.user.ColumnValue;
import mil.nga.sf.GeometryType;
import mil.nga.sf.Point;
import mil.nga.sf.Polygon;
import mil.nga.sf.LineString;
import mil.nga.sf.proj.Projection;
import mil.nga.sf.proj.ProjectionConstants;
import mil.nga.sf.proj.ProjectionFactory;
import mil.nga.sf.MultiPolygon;
import mil.nga.sf.Point;

/**
 * GPKG文件操作类，包括对GPKG的数据插入、删除、修改和查询等操作
 * 
 * @author cqwensten 2020-08-05
 *  email:cqwensten@163.com 
 *
 */
public class GpkgUtil {
	//WGS_1984_Web_Mercator_Auxiliary_Sphere:3857
	//GCS_WGS_1984:4326
	public static final long gpkg_defaultSrsId = 3857;
	public static final String gpkg_geom = "the_geom";
	public static final String gpkg_pkColumnId = "id";
	public static final String gpkg_pkColumnId2 = "objectid";
	public static final String gpkg_defaultTableName = "nongf_01";
	public static final String gpkg_uuid = "uuid";
	public static final String gpkg_collectid = "collectid";
	public static final String gpkg_templateCharset = "utf-8";
	
	
	/**
	 * Create the GeoPackage example file
	 * 
	 * @throws SQLException
	 *             upon error
	 * @throws IOException
	 *             upon error
	 */
	private static void create(String gpkgPath, Map<String,List<FieldInfo>> tabFieldInfoMap, long espg) throws SQLException, IOException {
		System.out.println("Creating: " + gpkgPath);
		GeoPackage geoPackage = createGeoPackage(gpkgPath);
		
		for(Entry<String, List<FieldInfo>> ent: tabFieldInfoMap.entrySet()) {
			//1-tableName
			String inTableName = ent.getKey();
			List<FieldInfo> additionFieldInfos = ent.getValue();
			
			GeometryColumns geometryColumns = new GeometryColumns();
			geometryColumns.setId(new TableColumnKey(inTableName, "geom"));
			geometryColumns.setGeometryType(GeometryType.POLYGON);
			geometryColumns.setZ((byte) 1);
			geometryColumns.setM((byte) 0);
	
			BoundingBox boundingBox = new BoundingBox(-90, -45, 90, 45);
	
			//2-数据表结构
			List<FeatureColumn> additionalColumns = getFeatureColumnsExcludePkIdAndGeom(additionFieldInfos);
	
			SpatialReferenceSystem srs = geoPackage.getSpatialReferenceSystemDao()
					.getOrCreateCode(ProjectionConstants.AUTHORITY_EPSG, espg);
			geometryColumns = geoPackage.createFeatureTableWithMetadata(
					geometryColumns, additionalColumns, boundingBox, srs.getId());
		}

		//validateFeatureTableWithMetadata(geoPackage, geometryColumns, null, additionalColumns);
		
	}
	
	private static void create(String gpkgPath, String geotype, Map<String,List<FieldInfo>> tabFieldInfoMap, long espg) throws Exception {
		System.out.println("Creating: " + gpkgPath);
		GeoPackage geoPackage = createGeoPackage(gpkgPath);
		
		//几何类型
				GeometryType geoType = GeometryType.POLYGON;
				switch(geotype.toUpperCase()) {
					case "POINT":{
						geoType = GeometryType.POINT;
						break;
					}
					case "POLYLINE":
					case "LINESTRING":{
						geoType = GeometryType.LINESTRING;
						break;
					}
					case "POLYGON":{
						geoType = GeometryType.POLYGON;
						break;
					}
					case "MULTIPOLYGON":{
						geoType = GeometryType.MULTIPOLYGON;
						break;
					}
					default:
					{
						String errorMsg = String.format("geotype: %s 不支持的几何类型",geotype);
						throw new Exception(errorMsg);
					}
				}
		
		for(Entry<String, List<FieldInfo>> ent: tabFieldInfoMap.entrySet()) {
			//1-tableName
			String inTableName = ent.getKey();
			List<FieldInfo> additionFieldInfos = ent.getValue();
			
			GeometryColumns geometryColumns = new GeometryColumns();
			geometryColumns.setId(new TableColumnKey(inTableName, "geom"));
			geometryColumns.setGeometryType(geoType);
			geometryColumns.setZ((byte) 1);
			geometryColumns.setM((byte) 0);
	
			BoundingBox boundingBox = new BoundingBox(-90, -45, 90, 45);
	
			//2-数据表结构
			List<FeatureColumn> additionalColumns = getFeatureColumnsExcludePkIdAndGeom(additionFieldInfos);
	
			SpatialReferenceSystem srs = geoPackage.getSpatialReferenceSystemDao()
					.getOrCreateCode(ProjectionConstants.AUTHORITY_EPSG, espg);
			geometryColumns = geoPackage.createFeatureTableWithMetadata(
					geometryColumns, additionalColumns, boundingBox, srs.getId());
		}

		//validateFeatureTableWithMetadata(geoPackage, geometryColumns, null, additionalColumns);
		
	}
	
	private static GeoPackage createGeoPackage(String gpkgPath) {
		File file = new File(gpkgPath);
		if (file.exists()) {
			file.delete();
		}

		GeoPackage geoPackage=null;
		if(GeoPackageManager.create(file)==true) {
			geoPackage= GeoPackageManager.open(file);
		}

		return geoPackage;
	}
	
	
	
	/**
	 * wkt2json wkt转换为json
	 * 
	 * @param wkt
	 * @param map 相关的属性：字段和字段值
	 * @return
	 */
	public static String wkt2json(String wkt, Map<String, Object> map) {
		String jsonStr = null;

		try {
			StringWriter writer = new StringWriter();

			WKTReader reader = new WKTReader();
			Geometry geo = reader.read(wkt);
			// org.geotools.geojson.geom.GeometryJSON
			GeometryJSON geoJson = new GeometryJSON();
			geoJson.write(geo, writer);
			map.put("geometry", writer);

			jsonStr = JSONObject.toJSONString(map);

		} catch (Exception e) {
			e.printStackTrace();
		}
		return jsonStr;
	}

	/**
	 * json2Wkt geojson转换为wkt
	 * 
	 * @param gjsonStr 这里要求是com.vividsolutions.jts.geom.Geometry的geojson字符串
	 * 
	 * @return
	 */
	public static String json2Wkt(String gjsonStr) {
		String wkt = null;
		GeometryJSON gjson = new GeometryJSON();
		Reader reader = new StringReader(gjsonStr);
		try {
			// 要求传入的是com.vividsolutions.jts.geom.Geometry
			Geometry geometry = gjson.read(reader);
			wkt = geometry.toText();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return wkt;
	}

	/**
	 * getColumnTypeByName 根据字段名称, 读取template模板中该字段的类型
	 * 
	 * @param template   模板
	 * @param columnName 字段(列)名称
	 * 
	 * @return
	 */
	public static String getColumnTypeByName(GpkgTemplate template, String columnName) {
		String columnType = "";
		List<FieldInfo> fieldInfos = template.getFieldInfos();

		Iterator<FieldInfo> iter = fieldInfos.iterator();
		while (iter.hasNext()) {
			FieldInfo fieldInfo = iter.next();
			if (fieldInfo.getName().equalsIgnoreCase(columnName)) {
				columnType = fieldInfo.getType();
				break;
			}
		}
		return columnType;
	}
	
	/**
	 * getColumnIndexByName 根据字段名称(判断过程忽略大小写), 读取template模板中该字段的索引号；当未匹配时，返回为-1
	 * 
	 * @param template   模板
	 * @param columnName 字段(列)名称
	 * 
	 * @return 字段索引号
	 */
	public static int getColumnIndexByName(GpkgTemplate template, String columnName) {
		int columnIndex = -1;
		List<FieldInfo> fieldInfos = template.getFieldInfos();

		Iterator<FieldInfo> iter = fieldInfos.iterator();
		while (iter.hasNext()) {
			FieldInfo fieldInfo = iter.next();
			if (fieldInfo.getName().equalsIgnoreCase(columnName)) {
				columnIndex = fieldInfo.getIndex();
				break;
			}
		}
		return columnIndex;
	}

	/**
	 * Create a point
	 * @param x
	 * @param y
	 * @return
	 */
	public static Point createPoint(double x, double y) {
		Point point = new Point(false, false, x, y);
		return point;
	}

	/**
	 * buildGpkgDB- 根据字段结构，构建一个新的gpkg文件数据库
	 * 
	 * @param gpkgFilePath gpkgFile路径
	 * @param intableName  gpkg内部表名称
	 * @param additionFieldInfos  属性表字段集
	 * @param espg  投影espg
	 * 
	 * @throws SQLException
	 */
	public static void buildGpkgDB(String gpkgFilePath, String intableName, 
			List<FieldInfo> additionFieldInfos, long espg) throws SQLException {
		GeometryType geoType = GeometryType.POLYGON;
		File dbFile = new File(gpkgFilePath);
		if(dbFile.exists()) {
			//如果存在，则删除
			dbFile.delete();
		}
		
		//1-Gpkg文件
		GeoPackageManager.create(dbFile);
		GeoPackage geoPackage = GeoPackageManager.open(dbFile);
		if (geoPackage == null) {
			throw new GeoPackageException("Failed to open gpkg database");
		}
		
		//2-数据表结构
		List<FeatureColumn> additionalColumns = getFeatureColumnsExcludePkIdAndGeom(additionFieldInfos);

		//3-geom图形
		GeometryColumns geometryColumns = new GeometryColumns();
		TableColumnKey geomColumnKey = new TableColumnKey(intableName, "geom");
		geometryColumns.setId(geomColumnKey);
		geometryColumns.setGeometryType(geoType);
		geometryColumns.setZ((byte) 0);
		geometryColumns.setM((byte) 0);
		
		//4-图形范围及投影
		BoundingBox boundingBox = new BoundingBox(-180, -45, 180, 45);
		//SpatialReferenceSystem srs = geoPackage.getSpatialReferenceSystemDao().getOrCreateCode(
		//      ProjectionConstants.AUTHORITY_EPSG, ProjectionConstants.EPSG_WEB_MERCATOR);
		
		SpatialReferenceSystem srs = geoPackage.getSpatialReferenceSystemDao()
				.getOrCreateCode(ProjectionConstants.AUTHORITY_EPSG, espg);
		
		String pkidColumn = GpkgUtil.gpkg_pkColumnId;
		GeometryColumns resgeometryColumns = geoPackage.createFeatureTableWithMetadata(
				geometryColumns, pkidColumn, additionalColumns, boundingBox, srs.getId());

		geoPackage.close();
	}
	
	public static ResInfo buildGpkgDB(String gpkgFilePath, 
			String geotype, String intableName, 
			List<FieldInfo> additionFieldInfos, long espg) throws Exception {
		ResInfo resInfo = new ResInfo();
		//几何类型
		GeometryType geomType = GeometryType.POLYGON;
		switch(geotype.toUpperCase()) {
			case "POINT":{
				geomType = GeometryType.POINT;
				break;
			}
			case "POLYLINE":
			case "LINESTRING":{
				geomType = GeometryType.LINESTRING;
				break;
			}
			case "POLYGON":{
				geomType = GeometryType.POLYGON;
				break;
			}
			case "MULTIPOLYGON":{
				geomType = GeometryType.MULTIPOLYGON;
				break;
			}
			default:
			{
				String errorMsg = String.format("geotype: %s 不支持的几何类型",geotype);
				resInfo.setCode(500);
				resInfo.setStatus(ResInfo.ERROR);
				resInfo.setMsg(errorMsg);
				throw new Exception(errorMsg);
			}
		}
		
		File dbFile = new File(gpkgFilePath);
		if(dbFile.exists()) {
			//如果存在，则删除
			dbFile.delete();
		}
		
		//1-Gpkg文件
		GeoPackageManager.create(dbFile);
		GeoPackage geoPackage = GeoPackageManager.open(dbFile);
		if (geoPackage == null) {
			String errorMsg = String.format("Failed to open gpkg database");
			resInfo.setCode(500);
			resInfo.setStatus(ResInfo.ERROR);
			resInfo.setMsg(errorMsg);
			
			throw new GeoPackageException("Failed to open gpkg database");
		}
		
		//2-数据表结构
		List<FeatureColumn> columns = getFeatureColumnsExcludePkIdAndGeom(additionFieldInfos);
		//List<FeatureColumn> columns = getFeatureColumnsIncludePkIdAndGeom(additionFieldInfos);
		
		for(FeatureColumn feaColumn: columns) {
			System.out.println(String.format("--->index: %d, name:%s, type:%s",feaColumn.getIndex(), feaColumn.getName(), feaColumn.getType()));
		}
		//3-geom图形
		GeometryColumns geometryColumns = new GeometryColumns();
		TableColumnKey geomColumnKey = new TableColumnKey(intableName, "geom");
		geometryColumns.setId(geomColumnKey);
		geometryColumns.setGeometryType(geomType);
		geometryColumns.setZ((byte) 0);
		geometryColumns.setM((byte) 0);
		
		
		//4-图形范围及投影
		BoundingBox boundingBox = new BoundingBox(-180, -45, 180, 45);
		//SpatialReferenceSystem srs = geoPackage.getSpatialReferenceSystemDao().getOrCreateCode(
		//      ProjectionConstants.AUTHORITY_EPSG, ProjectionConstants.EPSG_WEB_MERCATOR);

		//SpatialReferenceSystem srs = geoPackage.getSpatialReferenceSystemDao().createWebMercator();
		
		SpatialReferenceSystem srs = geoPackage.getSpatialReferenceSystemDao().getOrCreateCode(
				ProjectionConstants.AUTHORITY_EPSG, espg);
		
		long srsId = srs.getId();
		String pkidColumn = GpkgUtil.gpkg_pkColumnId;
		String geomColumn = GpkgUtil.gpkg_geom;
		
		//不带id和geom字段的
		GeometryColumns resgeometryColumns = geoPackage.createFeatureTableWithMetadata(geometryColumns, pkidColumn, columns, boundingBox, srs.getId());
		//自定义pkid和geom字段
		//GeometryColumns resgeometryColumns = geoPackage.createFeatureTableWithMetadata(geometryColumns, boundingBox, srsId, columns);
		String geoColumnName = resgeometryColumns.getColumnName();
		
		geoPackage.close();
		
		String msgOfSuccess = String.format("--->buildGpkgDB success, gpkgFilePath: %s ,intableName: %s, geotype: %s, espg: %d", 
				gpkgFilePath, intableName, geotype, espg);
		resInfo.setCode(200);
		resInfo.setStatus(ResInfo.SUCCESS);
		resInfo.setMsg(msgOfSuccess);
		resInfo.setRes(gpkgFilePath);
		
		return resInfo;
	}
	
	public static void buildGpkgDB(String gpkgFilePath, String geotype, Map<String, GpkgTemplate> templateMap) throws SQLException {
		GeometryType geomType = GeometryType.POLYGON;
		// 几何类型
		switch (geotype.toUpperCase()) {
		case "POINT": {
			geomType = GeometryType.POINT;
			break;
		}
		case "POLYLINE":
		case "LINESTRING": {
			geomType = GeometryType.LINESTRING;
			break;
		}
		case "POLYGON": {
			geomType = GeometryType.POLYGON;
			break;
		}
		case "MULTIPOLYGON": {
			geomType = GeometryType.MULTIPOLYGON;
			break;
		}
		default: {
			String errorMsg = String.format("geotype: %s 不支持的几何类型", geotype);
			System.out.println(errorMsg);
		}
		}
		File dbFile = new File(gpkgFilePath);
		if (dbFile.exists()) {
			// 如果存在，则删除
			dbFile.delete();
		}
		
		//1-Gpkg文件
		GeoPackageManager.create(dbFile);
		GeoPackage geoPackage = GeoPackageManager.open(dbFile);
		if (geoPackage == null) {
			throw new GeoPackageException("Failed to open gpkg database");
		}
		
	    for(Entry<String, GpkgTemplate> ent: templateMap.entrySet()) {
	    	String inTableKey = ent.getKey();
	    	//1-表定义
	    	GpkgTemplate template = ent.getValue();
	    	String tableName = template.getTableName();
	    	long espg = template.getSrsId();
	    	
	    	//2-数据表结构
	    	List<FieldInfo> additionFieldInfos = template.getFieldInfos(); 
			List<FeatureColumn> additionalColumns = getFeatureColumnsExcludePkIdAndGeom(additionFieldInfos);

			//3-geom图形
			GeometryColumns geometryColumns = new GeometryColumns();
			TableColumnKey geomColumnKey = new TableColumnKey(tableName, "geom");
			geometryColumns.setId(geomColumnKey);
			geometryColumns.setGeometryType(geomType);
			geometryColumns.setZ((byte) 0);
			geometryColumns.setM((byte) 0);
			
			//4-图形范围及投影
			BoundingBox boundingBox = new BoundingBox(-180, -45, 180, 45);
			//SpatialReferenceSystem srs = geoPackage.getSpatialReferenceSystemDao().getOrCreateCode(
			//      ProjectionConstants.AUTHORITY_EPSG, ProjectionConstants.EPSG_WEB_MERCATOR);
			
			SpatialReferenceSystem srs = geoPackage.getSpatialReferenceSystemDao()
					.getOrCreateCode(ProjectionConstants.AUTHORITY_EPSG, espg);
			
			String pkidColumn = GpkgUtil.gpkg_pkColumnId;
			
			GeometryColumns resgeometryColumns = geoPackage.createFeatureTableWithMetadata(
					geometryColumns, pkidColumn, additionalColumns, boundingBox, srs.getId());		
	    }
	    
		geoPackage.close();
	}
	
	
	/**
	 * getFeatureColumns-模板字段转换，不带图形和id字段
	 * 
	 * @param addfieldInfos
	 * @return
	 */
	public static List<FeatureColumn> getFeatureColumnsExcludePkIdAndGeom(List<FieldInfo> addfieldInfos) {
		List<FeatureColumn> columns = new ArrayList<FeatureColumn>();

		for(int i=0; i<addfieldInfos.size(); i++) {
			FieldInfo fieldInfo = addfieldInfos.get(i);
			
			int fieldIndex = fieldInfo.getIndex();
			String fieldName = fieldInfo.getName();
			String fieldType = fieldInfo.getType();
			long fieldLength = fieldInfo.getLength();
			
			// fieldName,排除id和geom图形字段
			if ( StringUtil.isNullOrEmpty(fieldName) || GpkgUtil.gpkg_pkColumnId.equalsIgnoreCase(fieldName)
					|| "geom".equalsIgnoreCase(fieldName) || "the_geom".equalsIgnoreCase(fieldName) ) {
				continue;
			}
			//字段名称统一小写，很重要
			fieldName=fieldName.toLowerCase();
			
			// 根据类型进行判断
			switch (fieldType.toUpperCase()) {
			case "STRING":
			case "TEXT":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName,
						GeoPackageDataType.TEXT, fieldLength));
				break;
//			case "MEDIUMINT":
//				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName, 
//						GeoPackageDataType.MEDIUMINT));
			case "INT":
			case "INTEGER":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName, 
						GeoPackageDataType.MEDIUMINT));
				break;
			case "LONG":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName,
						GeoPackageDataType.INTEGER));
				break;
			case "FLOAT":
			case "REAL":
			case "DOUBLE":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName,
						GeoPackageDataType.DOUBLE));
				break;
			case "DATE":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName,
						GeoPackageDataType.DATE));
				break;
			case "DATETIME":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName,
						GeoPackageDataType.DATETIME));
				break;
			case "BLOB":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName,
						GeoPackageDataType.BLOB));
				break;
			}
		}

		return columns;
	}
	
	public static List<FeatureColumn> getFeatureColumnsIncludePkIdAndGeom(List<FieldInfo> addfieldInfos) {
		List<FeatureColumn> columns = new ArrayList<FeatureColumn>();

		for (int i = 0; i < addfieldInfos.size(); i++) {
			FieldInfo fieldInfo = addfieldInfos.get(i);

			int fieldIndex = fieldInfo.getIndex();
			String fieldName = fieldInfo.getName();
			String fieldType = fieldInfo.getType();
			long fieldLength = fieldInfo.getLength();

			// 字段名称统一小写，很重要
			fieldName = fieldName.toLowerCase();

			// fieldName 如已存在该字段名称，则跳过
			if (StringUtil.isNullOrEmpty(fieldName)) {
				continue;
			}
			
			if ( GpkgUtil.gpkg_pkColumnId.equalsIgnoreCase(fieldName)) {
				FeatureColumn pkIdColumn = FeatureColumn.createPrimaryKeyColumn(fieldName);
				columns.add(pkIdColumn);
				continue;
			}

			// 根据类型进行判断
			switch (fieldType.toUpperCase()) {
				case "STRING":
				case "TEXT":
					columns.add(FeatureColumn.createColumn(fieldIndex, fieldName, GeoPackageDataType.TEXT, fieldLength));
					break;
				case "MEDIUMINT":
					columns.add(FeatureColumn.createColumn(fieldIndex, fieldName, GeoPackageDataType.MEDIUMINT));
				case "INT":
				case "INTEGER":
				case "LONG":
					columns.add(FeatureColumn.createColumn(fieldIndex, fieldName, GeoPackageDataType.INTEGER));
					break;
				case "FLOAT":
				case "REAL":
				case "DOUBLE":
					columns.add(FeatureColumn.createColumn(fieldIndex, fieldName, GeoPackageDataType.DOUBLE));
					break;
				case "DATE":
					columns.add(FeatureColumn.createColumn(fieldIndex, fieldName, GeoPackageDataType.DATE));
					break;
				case "DATETIME":
					columns.add(FeatureColumn.createColumn(fieldIndex, fieldName, GeoPackageDataType.DATETIME));
					break;
	
				case "BLOB": {
					columns.add(FeatureColumn.createColumn(fieldIndex, fieldName, GeoPackageDataType.BLOB));
					break;
				}
	
				// 几何图形字段
				case "POINT": {
					FeatureColumn geomColumn = FeatureColumn.createGeometryColumn(fieldName, GeometryType.POINT);
					columns.add(geomColumn);
					break;
				}
				case "POLYLINE":
				case "LINESTRING": {
					FeatureColumn geomColumn = FeatureColumn.createGeometryColumn(fieldName, GeometryType.LINESTRING);
					columns.add(geomColumn);
					break;
				}
				case "POLYGON": {
					FeatureColumn geomColumn = FeatureColumn.createGeometryColumn(fieldName, GeometryType.POLYGON);
					columns.add(geomColumn);
					break;
				}
				case "MULTIPOLYGON": {
					fieldName="geom";
					FeatureColumn geomColumn = FeatureColumn.createGeometryColumn(fieldName, GeometryType.MULTIPOLYGON);
					columns.add(geomColumn);
					break;
				}
			}
		}

		return columns;
	}
	
	
	/**
	 * Build an example feature table
	 * 
	 * @param tableName
	 * @param geometryColumn
	 * @param geometryType
	 * @return feature table
	 */
	public static FeatureTable buildFeatureTable(String tableName, String geometryColumn, GeometryType geometryType, 
			List<FieldInfo> addfieldInfos) {

		List<FeatureColumn> columns = new ArrayList<FeatureColumn>();
		columns.add(FeatureColumn.createPrimaryKeyColumn(0, GpkgUtil.gpkg_pkColumnId));
		columns.add(FeatureColumn.createGeometryColumn(1, geometryColumn,
				geometryType));

		for(int i=0; i<addfieldInfos.size(); i++) {
			FieldInfo fieldInfo = addfieldInfos.get(i);
			
			int fieldIndex = fieldInfo.getIndex();
			String fieldName = fieldInfo.getName();
			String fieldType = fieldInfo.getType();
			long fieldLength = fieldInfo.getLength();
			
			// fieldName 如已存在该字段名称，则跳过
			if ( StringUtil.isNullOrEmpty(fieldName) || "fid".equalsIgnoreCase(fieldName)
					|| "geom".equalsIgnoreCase(fieldName) ) {
				continue;
			}
			//字段名称统一小写,很重要
			fieldName=fieldName.toLowerCase();
			// 根据类型进行判断
			switch (fieldType.toUpperCase()) {
			case "STRING":
			case "TEXT":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName,
						GeoPackageDataType.TEXT, fieldLength));
				break;
			case "INT":
			case "INTEGER":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName,
						GeoPackageDataType.INTEGER));
				break;
			case "FLOAT":
			case "REAL":
			case "DOUBLE":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName,
						GeoPackageDataType.DOUBLE));
				break;
			case "DATE":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName,
						GeoPackageDataType.DATE));
				break;
			case "DATETIME":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName,
						GeoPackageDataType.DATETIME));
				break;
			case "BLOB":
				columns.add(FeatureColumn.createColumn(fieldIndex, fieldName,
						GeoPackageDataType.BLOB));
				break;
			}
		}

		FeatureTable table = new FeatureTable(tableName, geometryColumn, columns);

		return table;
	}

	/**
	 * getGpkgTemplates 获取一个gpkg文件的所有信息，包括模板字段定义等
	 * 
	 * @param filepath gpkg文件物理路径
	 * 
	 * @return
	 */
	public static List<GpkgTemplate> getGpkgTemplates(String filepath) {
		List<GpkgTemplate> templates = new ArrayList<GpkgTemplate>();

		File existingGeoPackage = new File(filepath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);

		// Feature and tile tables
		List<String> feaTables = geoPackage.getFeatureTables();

		int feaTableCount = feaTables.size();
		if (feaTableCount > 0) {
			for (int i = 0; i < feaTableCount; i++) {
				String tableName = feaTables.get(i);
				FeatureDao featureDao = geoPackage.getFeatureDao(tableName);

				System.out.println(String.format("--->index: %d, tableName: %s", i, tableName));

				GpkgTemplate gpkgTemplate = new GpkgTemplate();
				// tableName
				gpkgTemplate.setId(i);
				gpkgTemplate.setTableName(tableName);

				// projection 投影
				long srsId = featureDao.getContents().getSrsId();
				gpkgTemplate.setSrsId(srsId);

				// fieldInfos
				List<FeatureColumn> feaColumns = featureDao.getColumns();
				int columnCount = feaColumns.size();
				for (int j = 0; j < columnCount; j++) {
					FeatureColumn feaColumn = feaColumns.get(j);
					// 序号
					int columnIndex = feaColumn.getIndex();
					String columnName = feaColumn.getName();
					String columnType = feaColumn.getType();

					FieldInfo fieldInfo = new FieldInfo();
					fieldInfo.setIndex(columnIndex);
					//字段名小写
					fieldInfo.setName(columnName.toLowerCase());
					fieldInfo.setType(columnType);
					fieldInfo.setAlias(columnName);

					gpkgTemplate.getFieldInfos().add(fieldInfo);
				}

				templates.add(gpkgTemplate);
			}
		}
		
		geoPackage.close();
		return templates;
	}
	
	public static Map<String,GpkgTemplate> getGpkgTemplateMap(String filepath) {
		Map<String,GpkgTemplate> templateMap = new HashMap<String,GpkgTemplate>();

		File existingGeoPackage = new File(filepath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);

		// Feature and tile tables
		List<String> feaTables = geoPackage.getFeatureTables();

		int feaTableCount = feaTables.size();
		if (feaTableCount > 0) {
			for (int i = 0; i < feaTableCount; i++) {
				String tableName = feaTables.get(i);
				FeatureDao featureDao = geoPackage.getFeatureDao(tableName);

				System.out.println(String.format("--->index: %d, tableName: %s", i, tableName));

				GpkgTemplate gpkgTemplate = new GpkgTemplate();
				// tableName
				gpkgTemplate.setId(i);
				gpkgTemplate.setTableName(tableName);

				// projection 投影
				long srsId = featureDao.getContents().getSrsId();
				gpkgTemplate.setSrsId(srsId);

				// fieldInfos
				List<FeatureColumn> feaColumns = featureDao.getColumns();
				int columnCount = feaColumns.size();
				for (int j = 0; j < columnCount; j++) {
					FeatureColumn feaColumn = feaColumns.get(j);
					// 序号
					int columnIndex = feaColumn.getIndex();
					String columnName = feaColumn.getName();
					String columnType = feaColumn.getType();

					FieldInfo fieldInfo = new FieldInfo();
					fieldInfo.setIndex(columnIndex);
					//字段名小写
					fieldInfo.setName(columnName.toLowerCase());
					fieldInfo.setType(columnType);
					fieldInfo.setAlias(columnName);

					gpkgTemplate.getFieldInfos().add(fieldInfo);
				}

				templateMap.put(tableName , gpkgTemplate);
			}
		}
		
		geoPackage.close();
		return templateMap;
	}
	
	public static GpkgTemplate getGpkgTemplate(GeoPackage gpkg,String tableName) {
		FeatureDao featureDao = gpkg.getFeatureDao(tableName);
		GpkgTemplate gpkgTemplate = new GpkgTemplate();
		// tableName
		gpkgTemplate.setId(0);
		gpkgTemplate.setTableName(tableName);

		// projection 投影
		long srsId = featureDao.getContents().getSrsId();
		gpkgTemplate.setSrsId(srsId);

		// fieldInfos
		List<FeatureColumn> feaColumns = featureDao.getColumns();
		int columnCount = feaColumns.size();
		for (int j = 0; j < columnCount; j++) {
			FeatureColumn feaColumn = feaColumns.get(j);
			// 序号
			int columnIndex = feaColumn.getIndex();
			String columnName = feaColumn.getName();
			String columnType = feaColumn.getType();

			FieldInfo fieldInfo = new FieldInfo();
			fieldInfo.setIndex(columnIndex);
			//字段名小写
			fieldInfo.setName(columnName.toLowerCase());
			fieldInfo.setType(columnType);
			fieldInfo.setAlias(columnName.toLowerCase());

			gpkgTemplate.getFieldInfos().add(fieldInfo);
		}
		return gpkgTemplate;
	}
	
	public static GpkgTemplate loadGpkgTemplate(String filePath) {
		GpkgTemplate gpkgTemplate=null;
		File templeFile = new File(filePath);
		String context;
		try {
			context = FileUtil.readFile(templeFile, gpkg_templateCharset);
			if( !StringUtil.isNullOrEmpty(context) ) {
				gpkgTemplate = JSONObject.parseObject(context, GpkgTemplate.class);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return gpkgTemplate;
	}
	
	public static void saveGpkgTemplateToFile(GpkgTemplate template,String filePath) {
		try {
			String content = JSONObject.toJSONString(template);
			FileUtil.writeFile(content, filePath, gpkg_templateCharset);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void saveGpkgTemplateToFile(List<GpkgTemplate> templates,String filePath) {
		try {
			String content = JSONObject.toJSONString(templates);
			FileUtil.writeFile(content, filePath, gpkg_templateCharset);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void saveGpkgTemplateToFile(Map<String,GpkgTemplate> templates,String filePath) {
		try {
			String content = JSONObject.toJSONString(templates);
			FileUtil.writeFile(content, filePath, gpkg_templateCharset);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	
	
	/**
	 * addFieldsToGpkgTemplate 添加字段到Gpkg文件中
	 * 
	 * @param filepath  gpkg路径
	 * @param addfieldInfos 字段列表
	 * 
	 * @return  默认的Gpkg模板
	 */
	public static GpkgTemplate addFieldsToGpkgTemplate(String filepath, List<FieldInfo> addfieldInfos){
		File existingGeoPackage = new File(filepath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);

		// Feature and tile tables
		List<String> feaTables = geoPackage.getFeatureTables();
		int feaTableCount = feaTables.size();
		if (feaTableCount <= 0) {
			geoPackage.close();
			return null;
		}
		
		String tableName = feaTables.get(0);
		AttributesDao attriDao = geoPackage.getAttributesDao(tableName);
		//int rowCount = attriDao.count();

		AttributesTable table = attriDao.getTable();
		//int existingColumnsSize = table.getColumns().size();
		AttributesColumn pk = table.getPkColumn();
		// 存在的字段集合
		List<AttributesColumn> existingColumns = table.getColumns();
		Set<String> existingColumnsName = new HashSet<String>();
		for (int i = 0; i < existingColumns.size(); i++) {
			String fname = existingColumns.get(i).getName();
			existingColumnsName.add(fname.toLowerCase());
		}
		
		GpkgTemplate gpkgTemplate = new GpkgTemplate();
		attriDao.beginTransaction();
		int fieldSize = addfieldInfos.size();
		for (int j = 0; j < fieldSize; j++) {
			FieldInfo fieldInfo = addfieldInfos.get(j);

			String fieldName = fieldInfo.getName();
			String fieldType = fieldInfo.getType();
			String fieldLabel = fieldInfo.getAlias();
			// 如已存在该字段名称，则跳过
			if (StringUtil.isNullOrEmpty(fieldName) || existingColumnsName.contains(fieldName.toLowerCase())) {
				continue;
			}
			
			fieldName= fieldName.toLowerCase();
			// 根据类型进行判断
			switch (fieldType.toUpperCase()) {
			case "STRING":
			case "TEXT":
				attriDao.addColumn(AttributesColumn.createColumn(fieldName, GeoPackageDataType.TEXT, false, ""));
				break;
			case "INT":
			case "INTEGER":
				attriDao.addColumn(AttributesColumn.createColumn(fieldName, GeoPackageDataType.INTEGER, false, ""));
				break;
			case "FLOAT":
			case "REAL":
			case "DOUBLE":
				attriDao.addColumn(AttributesColumn.createColumn(fieldName, GeoPackageDataType.DOUBLE, false, ""));
				break;
			case "DATE":
				attriDao.addColumn(AttributesColumn.createColumn(fieldName, GeoPackageDataType.DATE));
				break;
			case "DATETIME":
				attriDao.addColumn(AttributesColumn.createColumn(fieldName, GeoPackageDataType.DATETIME));
				break;
			case "BLOB":
				attriDao.addColumn(AttributesColumn.createColumn(fieldName, GeoPackageDataType.BLOB));
				break;
			}
		}
		attriDao.endTransaction();

		// tableName
		gpkgTemplate.setId(0);
		gpkgTemplate.setTableName(tableName);

		// projection 投影
		FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
		long srsId = featureDao.getContents().getSrsId();
		gpkgTemplate.setSrsId(srsId);
		
		// 重新获取所有字段
		List<AttributesColumn> allColumns = table.getColumns();
		int allColumnCount = allColumns.size();
		for (int j = 0; j < allColumnCount; j++) {
			AttributesColumn attrColumn = allColumns.get(j);
			// 序号
			int columnIndex = attrColumn.getIndex();
			String columnName = attrColumn.getName();
			String columnType = attrColumn.getType();

			FieldInfo fieldInfo = new FieldInfo();
			fieldInfo.setIndex(columnIndex);
			fieldInfo.setName(columnName.toLowerCase());
			fieldInfo.setType(columnType);
			fieldInfo.setAlias(columnName);

			gpkgTemplate.getFieldInfos().add(fieldInfo);
		}
		
		geoPackage.close();		
		return gpkgTemplate;
	}

	/**
	 * readGpkg 读取解析xxx.gpkg文件，读取矢量要素后返回Features的geojson
	 * 
	 * 默认读取第一个图层
	 * 
	 * @param gpkgPath gpkg物理存放路径 例如E:\temp\gpkg\lv\lv.gpkg
	 * 
	 * @return geojson格式字符串 （GeoJson序列号后成果）
	 * @throws java.text.ParseException 
	 */
	public static GeoJson readGpkg(String gpkgPath){
		File existingGeoPackage = new File(gpkgPath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);
		GeoJson geoJson = new GeoJson();
		
		// Feature and tile tables
		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 注意，目前只读取了第一个表
			String tableName = feaTables.get(0);
			//模板
			GpkgTemplate template = getGpkgTemplate(geoPackage, tableName);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			
			List<GeoJsonFeature> features = new ArrayList<GeoJsonFeature>();
			
			FeatureResultSet cursor = featureDao.queryForAll();
			while (cursor.moveToNext()) {
				FeatureRow featureRow = cursor.getRow();
				//转换为gjson
				GeoJsonFeature fea = gpkgFea2Json(featureRow,template);
				
				features.add(fea);
			}
			geoJson.setFeatures(features);
			geoJson.setType("FeatureCollection");
		
			cursor.close();
		}
		// Close database when done
		geoPackage.close();

		return geoJson;
	}
	public static Map<String,GeoJson> readGpkgs(String gpkgPath){
		File existingGeoPackage = new File(gpkgPath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);
		Map<String, GeoJson> geoJsons = new HashMap<String,GeoJson>();
		
		// Feature and tile tables
		List<String> feaTables = geoPackage.getFeatureTables();
		for (String tableName : feaTables) {
			GeoJson geoJson = new GeoJson();
			// 注意，目前只读取了第一个表
			//String tableName = feaTables.get(0);
			//模板
			GpkgTemplate template = getGpkgTemplate(geoPackage, tableName);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			
			List<GeoJsonFeature> features = new ArrayList<GeoJsonFeature>();
			
			FeatureResultSet cursor = featureDao.queryForAll();
			while (cursor.moveToNext()) {
				FeatureRow featureRow = cursor.getRow();
				//转换为gjson
				GeoJsonFeature fea = gpkgFea2Json(featureRow,template);
				
				features.add(fea);
			}
			geoJson.setFeatures(features);
			geoJson.setType("FeatureCollection");
			geoJsons.put(tableName, geoJson);
			
			cursor.close();
		}
		// Close database when done
		geoPackage.close();

		return geoJsons;
	}
	
	public static List<mil.nga.sf.Geometry> printGeoCenterPoints(String gpkgPath){
		File existingGeoPackage = new File(gpkgPath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);
	
		List<mil.nga.sf.Geometry> list= new ArrayList<mil.nga.sf.Geometry>();
		// Feature and tile tables
		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables != null && feaTables.size() > 0) {
			for (int i = 0; i < feaTables.size(); i++) {
				//遍历所有表
				String tableName = feaTables.get(i);
				System.out.println();
				System.out.println("--->printGeoCenterPoints: " + tableName);

				// 模板
				GpkgTemplate template = getGpkgTemplate(geoPackage, tableName);
				FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
				FeatureResultSet cursor = featureDao.queryForAll();
				int index = 0;
				while (cursor.moveToNext()) {
					FeatureRow featureRow = cursor.getRow();
					// 转换为gjson
					GeoPackageGeometryData geometryData = featureRow.getGeometry();
					if (geometryData != null && !geometryData.isEmpty()) {
						mil.nga.sf.Geometry geometry = geometryData.getGeometry();
						GeometryType gType = geometry.getGeometryType();

						Point centerPt = geometry.getCentroid();
						double x = centerPt.getX();
						double y = centerPt.getY();
						System.out.println(String.format("--->id: %d, x: %f, y: %f", index, x, y));

						list.add(geometry);

						index++;
					}
				}

				cursor.close();
			}
		}
		// Close database when done
		geoPackage.close();

		return list;
	}
	
	/**
	 * getGpkgAllUUIDSet 根据条件，获取一个GPKG文件中的所有UUID序列
	 * 
	 * @param filepath       gpkg物理文件路径 例如E:\temp\gpkg\lv\lv.gpkg
	 * @param mapFieldValues 一个Map<String,String>对象，包含了字段名和字段值。如果查询所有，这设置为null即可
	 * 
	 * @return UUID字段的 Set<String>
	 */
	public static Set<String> getGpkgUUIDSet(String filepath, Map<String, String> mapFieldValues) {
		Set<String> uuidSet = new HashSet<String>();

		// geoPackage
		File existingGeoPackage = new File(filepath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);
		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 当前，默认只处理第一个表
			String tableName = feaTables.get(0);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);

			// 1-根据字段和字段值进行条件查询
			if (mapFieldValues != null && !mapFieldValues.isEmpty()) {
				Set<String> keySet = mapFieldValues.keySet();
				for (String key : keySet) {
					String keyValue = mapFieldValues.get(key);
					FeatureResultSet cursor = featureDao.queryForEq(key, new ColumnValue(keyValue));
					while (cursor.moveToNext()) {
						FeatureRow featureRow = cursor.getRow();
						FeatureColumn column = featureRow.getColumn(gpkg_uuid);
						if (column != null) {
							Object val = featureRow.getValue(column.getName());
							if(!StringUtil.isNullOrEmpty(val)) {
								String uuid = val.toString();

								uuidSet.add(uuid);
							}
						}
					}
					cursor.close();
				}
			} else {
				// 2-获得所有的UUID所有
				FeatureResultSet cursor = featureDao.queryForAll();
				//int resCount = cursor.getCount();
				while (cursor.moveToNext()) {
					FeatureRow featureRow = cursor.getRow();
					FeatureColumn column = featureRow.getColumn(gpkg_uuid);
					if ( column != null) {
						Object val = featureRow.getValue(column.getName());
						if(!StringUtil.isNullOrEmpty(val)) {
							String uuid = val.toString();
							uuidSet.add(uuid);
						}
					}
				}
				cursor.close();
			}
		}
		
		geoPackage.close();
		return uuidSet;
	}

	/**
	 * updateGpkg 更新gpkg数据内容，该方法将根据geojson字符串中的uuid进行查询，将匹配的记录进行更新
	 * 
	 * @param filepath        gpkg物理文件路径 例如E:\temp\gpkg\lv\lv.gpkg
	 * @param geoJson        新的geojson字符串( GeoJson对象序列化结果)
	 * @param bUpdateGeometry 是否更新图形，只有当该值为true时才更新图形
	 * 
	 * @return 返回更新成功的Uuid Set<>集合
	 * 
	 * @throws IOException
	 * @throws SQLException
	 */
	public static Set<String> updateGpkg(String filepath, GeoJson geoJson, boolean bUpdateGeometry) throws IOException, SQLException {
		Set<String> sucUuidSet = new HashSet<String>();
		
		List<GeoJsonFeature> feaList = geoJson.getFeatures();
		// geoPackage
		File existingGeoPackage = new File(filepath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);
		List<String> feaTables = geoPackage.getFeatureTables();
		
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(0);
			// String tableName = geometryColumns.getTableName();
			GpkgTemplate template = GpkgUtil.getGpkgTemplate(geoPackage, tableName);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			
			for (int i = 0; i < feaList.size(); i++) {
				GeoJsonFeature geoFea = feaList.get(i);
				// 属性
				Map<String, Object> newProperties = geoFea.getProperties();
				//不存在uuid字段
				if( StringUtil.isNullOrEmpty(newProperties.get(gpkg_uuid.toLowerCase()))){
					
					continue;
				}
				featureDao.beginTransaction();
				String uuidValue = newProperties.get(gpkg_uuid).toString();
				//查询待更新的行
				//String objectId = featureDao.getIdColumnName();
				FeatureResultSet cursor = featureDao.queryForEq(gpkg_uuid, new ColumnValue(uuidValue));
				//FeatureResultSet cursor = featureDao.queryForAll();
				//int resCount = cursor.getCount();

				while (cursor.moveToNext()) {
					FeatureRow featureRow = cursor.getRow();
					GeoJsonGeometry newGeom = geoFea.getGeometry();
					int res = 0;
					try {
						updateGpkgFeature(template, featureRow, newGeom, newProperties, bUpdateGeometry);
						res = featureDao.update(featureRow);
						featureDao.commit();
					} catch (Exception ex) {
						ex.printStackTrace();
						
						cursor.close();
						featureDao.endTransaction();
					} 

					if (res > 0) {
						sucUuidSet.add(uuidValue);
					}
				}
				cursor.close();
				featureDao.endTransaction();
			}
		}
		
		geoPackage.close();		
		return sucUuidSet;
	}

	/**
	 * updateGpkg 更新gpkg数据内容，该方法将根据geojson字符串中的uuid进行查询，将匹配的记录进行更新
	  *    注意这里有一个 Set<String> uuids参数，如果gpkg中没有该UUID，则放弃更新
	 * 
	 * @param gpkgPath        gpkg物理文件路径 例如E:\temp\gpkg\lv\lv.gpkg
	 * @param geoJson        GeoJson对象序列化结果
	 * @param bUpdateGeometry 是否更新图形，只有当该值为true时才更新图形
     * @param uuids           要素唯一UUID集合
	 * 
	 * @return 返回更新成功的Uuid Set<>集合
	 * 
	 * @throws IOException
	 * @throws SQLException
	 */
	public static Set<String> updateGpkg(String gpkgPath, GeoJson geoJson, boolean bUpdateGeometry,
			 Set<String> uuids) throws IOException, SQLException {
		Set<String> sucUuidSet = new HashSet<String>();
		
		List<GeoJsonFeature> feaList = geoJson.getFeatures();

		// geoPackage
		File existingGeoPackage = new File(gpkgPath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);
		List<String> feaTables = geoPackage.getFeatureTables();

		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(0);
			GpkgTemplate template = GpkgUtil.getGpkgTemplate(geoPackage, tableName);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			featureDao.beginTransaction();
			for (int i = 0; i < feaList.size(); i++) {
				GeoJsonFeature geoFea = feaList.get(i);
				// 图形中的属性
				Map<String, Object> newProperties = geoFea.getProperties();
				// UUID
				String uuidValue = newProperties.get(gpkg_uuid).toString();

				// 判断是否在更新图形中地块是否在更新列表中
				boolean bContain = false;
				for (String uuid : uuids) {
					if (uuid.equalsIgnoreCase(uuidValue)) {
						bContain = true;
					}
				}
				if (bContain == false) {
					continue;
				}

				// Query for field values
				// String objectId = featureDao.getIdColumnName();
				FeatureResultSet cursor = featureDao.queryForEq(gpkg_uuid, new ColumnValue(uuidValue));
				int resCount = cursor.getCount();

				System.out.println(String.format("--->update uuid= %d, count:%d ", uuidValue, resCount));

				while (cursor.moveToNext()) {
					FeatureRow featureRow = cursor.getRow();
					GeoJsonGeometry newGeom = geoFea.getGeometry();
					int res=0;
					try {
						//更新到FeatureRow
						updateGpkgFeature(template,featureRow, newGeom, newProperties, bUpdateGeometry);
						res = featureDao.update(featureRow);
						featureDao.commit();
					} catch (Exception ex) {
						ex.printStackTrace();
					} 
					if (res > 0) {
						sucUuidSet.add(uuidValue);
					}
				}
				cursor.close();
			}
			featureDao.endTransaction();
		}

		geoPackage.close();
		return sucUuidSet;
	}
	
	
	/**
	 * updateFeaProperties -根据FeatureProperties的UUID字段来更新gpkg文件的属性，可批量
	 * 
	 * @param gpkgPath  gpkg文件路径
	 * @param feaProperties  自定义属性对象FeatureProperties集合
	 * @return 处理成功的UUID集合Set<String>
	 * @throws Exception
	 */
	public static Set<String> updateFeaProperties(String gpkgPath, List<FeatureProperties> feaProperties) throws Exception{
		Set<String> sucUuidSet= new HashSet<String>();
		if(feaProperties ==null || feaProperties.size()==0) {
			return sucUuidSet;
		}
		// geoPackage
		File existingGeoPackage = new File(gpkgPath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);
		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(0);
			GpkgTemplate template = GpkgUtil.getGpkgTemplate(geoPackage, tableName);
			
			//遍历客户端提交的每一个FeatureProperties
			int num = feaProperties.size();
			for (int i = 0; i < feaProperties.size(); i++) {
				FeatureProperties feaProper = feaProperties.get(i);
				//UUID和待更新的属性集合
				String uuidValue = feaProper.getUuid();
				Map<String, Object> properties = feaProper.getProperties();
				
				FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
				featureDao.beginTransaction();
				FeatureResultSet cursor = featureDao.queryForEq(gpkg_uuid, new ColumnValue(uuidValue));
				int resCount = cursor.getCount();
				
				System.out.println(String.format("--->updateFeaProperties uuid= %s, count:%d ", uuidValue, resCount));
				try {
					cursor.moveToFirst();
					while (cursor.moveToNext()) {
						FeatureRow featureRow = cursor.getRow();
						//主键字段objectid
						String objectId = featureRow.getPkColumn().getName();
						//上传的待更新的字段列表
						Set<String> updatefieldSet = properties.keySet();
						for(String columnName: updatefieldSet) {
							if (!"shape".equalsIgnoreCase(columnName) && !gpkg_uuid.equalsIgnoreCase(columnName)
									&& !columnName.equalsIgnoreCase(objectId)) {
								//检查待更新的字段在gpkg文件中是否存在
								int indexOfField = featureRow.getColumnIndex(columnName);
								if(indexOfField <0) {
									continue;
								}
								
								Object proVal = properties.get(columnName);
								//若新值为null或者值没有变化
								if( proVal==null ) {
									continue;
								}
								// 根据模板判断字段类型
								String columnType = getColumnTypeByName(template, columnName);
								switch (columnType.toUpperCase()) {
									case "INT":
									case "INTEGER":
										int inewVal = 0;
										if (!StringUtil.isNullOrEmpty(proVal)) {
											inewVal = Integer.parseInt(String.valueOf(proVal));
										}
										featureRow.setValue(columnName, inewVal);
										break;
									case "STRING":
									case "TEXT":
										if (proVal != null) {
											featureRow.setValue(columnName, String.valueOf(proVal));
										}
										break;
									case "FLOAT":
									case "REAL":
									case "DOUBLE":
										double dnewVal = 0.0;
										if (!StringUtil.isNullOrEmpty(proVal)) {
											dnewVal = Double.parseDouble(String.valueOf(proVal));
										}
										featureRow.setValue(columnName, dnewVal);
										break;
									case "DATE":
										Date dateVal = null;
										if (!StringUtil.isNullOrEmpty(proVal)) {
											String dateStr= String.valueOf(proVal);
											dateVal = JodaDateTimeUtil.strToDate(String.valueOf(proVal));
										}
										featureRow.setValue(columnName, dateVal);
										break;
									case "DATETIME":
										String dateTimeStr_std = null; 
										if (!StringUtil.isNullOrEmpty(proVal)) {
											String dateStr = String.valueOf(proVal);
											DateTime dtime=JodaDateTimeUtil.strToDateTime(dateStr);
											dateTimeStr_std = JodaDateTimeUtil.dateTimeToStr(dtime);
										}
										featureRow.setValue(columnName, dateTimeStr_std);
										break;
									}
							}
						}
						int res = featureDao.update(featureRow);
						if (res > 0) {
							sucUuidSet.add(uuidValue);
						}

						featureDao.commit();
					}
				}catch (Exception ex) {
					ex.printStackTrace();
					throw ex;
				} finally {
					cursor.close();
				}
			}
		}

		geoPackage.close();		
		return sucUuidSet;
	}


	public static boolean copy2NewGpkg(String newGpkgPath, Map<String,GpkgTemplate> newTemplateMap, Map<String,GeoJson> geoJsons, Map<String, Map<String,FieldInfoMapping>> maps) {

		boolean bSuccess=false;
		
		
		// 读取old geoPackage的数据内容
		File gpkgFile = new File(newGpkgPath);
		GeoPackage geoPackage = GeoPackageManager.open(gpkgFile);
		List<String> feaTables = geoPackage.getFeatureTables();
		for (String tableName: feaTables) {
			//表名
			String inTableName = tableName;
			if("ZD".equalsIgnoreCase(tableName)) {
				inTableName = "宗地";
			}else if("FW".equalsIgnoreCase(tableName)) {
				inTableName = "房屋";
			}
			//gpkg字段模板
			GpkgTemplate template = newTemplateMap.get(tableName);
			Map<String,FieldInfoMapping> fieldInfoMappings = maps.get(tableName);
			
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			
			//开启事务操作
			featureDao.beginTransaction();
			
			FeatureResultSet cursor = featureDao.queryForAll();
			int count = cursor.getCount();
			System.out.println();
			System.out.println(String.format("--->tableName: %s, intableName: %s, 更新前的总要素 count: %d",tableName,inTableName,count));
			String objectId = featureDao.getIdColumnName();
			
			//根据原表名获取相应的数据内容
			GeoJson geoJson = geoJsons.get(inTableName);
			
			List<GeoJsonFeature> feaList = geoJson.getFeatures();
			for(int i=0; i<feaList.size(); i++) {
				GeoJsonFeature geoFea = feaList.get(i);

				//1-要素属性
				Map<String, Object> oldProperties = geoFea.getProperties();
				System.out.println(String.format("--->oldProperties: %d, %s" ,oldProperties.size(), oldProperties.toString()));
				//2-原字段进行映射
				Map<String, Object> newProperties = GpkgUtil.convertFieldInfoMapping(oldProperties,fieldInfoMappings);
				System.out.println(String.format("--->newProperties: %d, %s" ,newProperties.size(), newProperties.toString()));
				
				String uuidValue = "";
				if( !StringUtil.isNullOrEmpty( newProperties.get(gpkg_uuid)) ) {
					uuidValue = newProperties.get(gpkg_uuid).toString();
				}else {
					uuidValue = UUID.randomUUID().toString();
				}
				
				//3-要素图形
				GeoJsonGeometry newGeom = geoFea.getGeometry();

				long rowId =-1;
				try {
					//4-更新新建的FeatureRow，注意这里需要更新UUID字段
					FeatureRow featureRow = featureDao.newRow();					
					updateGpkgFeature3(template, featureRow, newGeom, newProperties, true);
					rowId = featureDao.insert(featureRow);
					
					featureDao.commit();
					
				} catch (GeoPackageException ex) {
					ex.printStackTrace();
				} catch (java.text.ParseException e) {
					e.printStackTrace();
				} catch (ParseException e) {
					e.printStackTrace();
				}
			}
			
			featureDao.endTransaction();
			cursor.close();
			bSuccess = true;
		}
		
		geoPackage.close();
		
		return bSuccess;
		
	}
	
	/**
	 * 原字段和映射字段的集合进行映射处理
	 * 
	 * @param oldProperties  老字段名及字段值
	 * @param mappings       字段映射mapping
	 * 
	 * @return
	 */
	public static Map<String, Object> convertFieldInfoMapping(Map<String, Object> oldProperties,Map<String, FieldInfoMapping> mappings) {
		Map<String, Object> newProperties = new HashMap<String,Object>();
		//遍历原始字段名，在映射字典中插值是否存在；
		for(Entry<String, Object> ent: oldProperties.entrySet()) {
			String propName = ent.getKey();
			Object propVal = ent.getValue();
			String propValStr = StringUtil.isNullOrEmpty(propVal)?"":propVal.toString() ;			
			System.out.println(String.format("%s : %s", propName, propValStr ));
			//如果存在，则进行字段映射，
			if( mappings.containsKey(propName)) {
				FieldInfoMapping fieldMapping = mappings.get(propName);
				//映射后的字段名
				String newName = fieldMapping.getMappingFieldName();

				newProperties.put(newName, propVal);
			}else {
				//若不存在则抛弃
				//newProperties.put(propName, propVal);
			}
		}
		
		return newProperties;
	}

	
	/**
	 * insertGpkg 向gpkg文件插入新的数据内容
	 * 
	 * @param filepath gpkg物理文件路径 例如E:\temp\gpkg\lv\lv.gpkg
	 * @param geoJson GeoJson对象序列化结果
	 * 
	 * @return 返回插入成功的Uuid Set<>集合
	 * 
	 * @throws IOException
	 * @throws SQLException
	 * @throws ParseException
	 */
	public static Set<String> insertGpkg(String filepath, GeoJson geoJson) throws IOException, SQLException, ParseException {
		Set<String> sucUuidSet = new HashSet<String>();
		List<GeoJsonFeature> feaList = geoJson.getFeatures();
		boolean bUpdateGeometry= true;
		
		// geoPackage
		File existingGeoPackage = new File(filepath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);
		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 注意，默认只处理第一个表
			String tableName = feaTables.get(0);
			
			GpkgTemplate template = GpkgUtil.getGpkgTemplate(geoPackage, tableName);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			featureDao.beginTransaction();
			for (int i = 0; i < feaList.size(); i++) {
				GeoJsonFeature geoFea = feaList.get(i);

				Map<String, Object> newProperties = geoFea.getProperties();
				//统一属性字段名为小写
				Map<String, Object> newPropertiesLow= new HashMap<String, Object>();
				for(Entry<String, Object> ent:  newProperties.entrySet()) {
					String key=ent.getKey();
					Object propValue= ent.getValue();
					
					newPropertiesLow.put(key.toLowerCase(), propValue);
				}
				String uuidValue = "";
				if( !StringUtil.isNullOrEmpty( newProperties.get(gpkg_uuid)) ) {
					uuidValue = newProperties.get(gpkg_uuid).toString();
				}else {
					uuidValue = UUID.randomUUID().toString();
				}
				
				GeoJsonGeometry newGeom = geoFea.getGeometry();
				//要素的索引,不判断是否已有UUID要素，直接插入
				FeatureResultSet cursor = featureDao.queryForAll();
				int count = cursor.getCount();
				System.out.println("更新前的总要素 count: " + count);
				
				
				String objectId = featureDao.getIdColumnName();
				long rowId =-1;
				try {
					FeatureRow featureRow = featureDao.newRow();
					//更新新建的FeatureRow，注意这里需要更新UUID字段
					updateGpkgFeature2(template, featureRow, 
							newGeom, newPropertiesLow, bUpdateGeometry);
					rowId = featureDao.insert(featureRow);
					featureDao.commit();
					
				} catch (GeoPackageException ex) {
					ex.printStackTrace();
				} catch (java.text.ParseException e) {
					e.printStackTrace();
				}
				if (rowId >= 0) {
					sucUuidSet.add(uuidValue);
				}
				cursor.close();
			}

			featureDao.endTransaction();
		}
		
		geoPackage.close();
		return sucUuidSet;
	}
	
	/**
	 * insertOrUpdateGpkg 插入或者更新已有UUID的Gpkg图形
	 * 
	 * @param filepath
	 * @param geoJson
	 * 
	 * @return 操作成功的UUIDs集合
	 * 
	 * @throws IOException
	 * @throws SQLException
	 * @throws ParseException
	 */
	public static Set<String> insertOrUpdateGpkg(String filepath, GeoJson geoJson)throws IOException, SQLException, ParseException {
		Set<String> sucUuidSet = new HashSet<String>();
		boolean bUpdateGeometry =true;
		List<GeoJsonFeature> feaList = geoJson.getFeatures();
		
		// geoPackage
		File existingGeoPackage = new File(filepath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);
		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(0);
			GpkgTemplate template = GpkgUtil.getGpkgTemplate(geoPackage, tableName);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			featureDao.beginTransaction();
			for (int i = 0; i < feaList.size(); i++) {
				GeoJsonFeature geoFea = feaList.get(i);

				Map<String, Object> newProperties = geoFea.getProperties();				
				String uuidValue = "";
				if(newProperties.get(gpkg_uuid)!=null) {
					//接收的UUID
					uuidValue = newProperties.get(gpkg_uuid).toString();
				}else {
					//生成UUID
					uuidValue = UUID.randomUUID().toString();
				}
				
				String objectId = featureDao.getIdColumnName();
				FeatureResultSet cursor = featureDao.queryForEq(gpkg_uuid, new ColumnValue(uuidValue));
				int count = cursor.getCount();				
				System.out.println("origin count: " + count);			
				if( count > 0 ) {
					//1-编辑更新
					while (cursor.moveToNext()) {
						FeatureRow featureRow = cursor.getRow();						
						GeoJsonGeometry newGeom = geoFea.getGeometry();
						
						int res=0;						
						try {
							//更新FeatureRow，不需要更新UUID
							updateGpkgFeature(template,featureRow, newGeom, newProperties, bUpdateGeometry);
							res = featureDao.update(featureRow);
							featureDao.commit();
							
						} catch (java.text.ParseException e) {
							e.printStackTrace();
						}
					    
						if (res > 0) {
							sucUuidSet.add(uuidValue);
						}
					}
					cursor.close();
				}
				else {
					//2-插入数据
					FeatureRow featureRow = featureDao.newRow();
					GeoJsonGeometry newGeom = geoFea.getGeometry();
					
					long rowId =-1;
					try {
						//更新新建的FeatureRow，需要更新UUID
						updateGpkgFeature2(template, featureRow, newGeom, newProperties, bUpdateGeometry);
						rowId = featureDao.insert(featureRow);
						featureDao.commit();
						
					} catch (java.text.ParseException e) {
						e.printStackTrace();
					}
					cursor.close();
					if (rowId >= 0) {
						sucUuidSet.add(uuidValue);
					}
				}
			}

			featureDao.endTransaction();
		}
		
		geoPackage.close();
		return sucUuidSet;
	}
	

	/**
	 * deleteGpkgByUUIDs 根据UUID结合删除相关记录
	 * 
	 * @param filepath gpkg物理文件路径 例如E:\temp\gpkg\lv\lv.gpkg
	 * @param uuidSet  UUID 集合
	 * @return
	 */
	public static Set<String> deleteGpkgByUUIDSet(String filepath, Set<String> uuidSet) {
		Set<String> sucUuidSet = new HashSet<String>();
		// geoPackage
		File existingGeoPackage = new File(filepath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);
		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(0);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			featureDao.beginTransaction();

			for (String uuidValue : uuidSet) {
				// 第一种
				/*
				 * Map<String, Object> fieldValues = new HashMap<String, Object>();
				 * fieldValues.put("uuid", uuidValue);
				 * 
				 * featureDao.delete(fieldValues); 
				 * featureDao.commit();
				 */

				// 第二种
				String objectId = featureDao.getIdColumnName();
				FeatureResultSet cursor = featureDao.queryForEq("uuid", new ColumnValue(uuidValue));
				int resCount = cursor.getCount();
				System.out.println();
				System.out.println(String.format("--->uuid: %s, count: %d  ", uuidValue, resCount));

				while (cursor.moveToNext()) {
					FeatureRow featureRow = cursor.getRow();
					int res=0;
					try {
						// 删除
						res = featureDao.delete(featureRow);
						featureDao.commit();
					} catch (Exception ex) {
						ex.printStackTrace();
					} 
					if (res > 0) {
						sucUuidSet.add(uuidValue);
					}
				}
				cursor.close();
				
			}

			featureDao.endTransaction();
		}
		
		geoPackage.close();
		return sucUuidSet;
	}

	/**
	 * queryByUUIDs 根据UUID结合查询相关要素
	 * 
	 * @param filepath gpkg物理文件路径 例如E:\temp\gpkg\lv\lv.gpkg
	 * @param uuidSet  UUID Set<>集合
	 * 
	 * @return 返回GeoJson序列化后的字符串
	 */
	public static GeoJson queryByUUIDSet(String filepath, Set<String> uuidSet) {
		// geoJson
		GeoJson geoJson = new GeoJson();
		List<GeoJsonFeature> features = new ArrayList<GeoJsonFeature>();

		// geoPackage
		File existingGeoPackage = new File(filepath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);

		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(0);
			GpkgTemplate template = GpkgUtil.getGpkgTemplate(geoPackage, tableName);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);

			for (String uuidValue : uuidSet) {
				FeatureResultSet cursor = featureDao.queryForEq(gpkg_uuid, new ColumnValue(uuidValue));
				int resCount = cursor.getCount();
				System.out.println();
				System.out.println(String.format("--->uuid: %s, count: %d  ", uuidValue, resCount));

				while (cursor.moveToNext()) {
					FeatureRow featureRow = cursor.getRow();
					//将gpkg的图形转换为gjson
					GeoJsonFeature fea = gpkgFea2Json(featureRow,template);
					
					features.add(fea);
				}
				cursor.close();
			}
		}

		geoJson.setFeatures(features);
		geoJson.setType("FeatureCollection");

		geoPackage.close();

		return geoJson;
	}

	public static GeoJson queryByNotEmpty(String filepath,String targetFieldName) {
		// geoJson
		GeoJson geoJson = new GeoJson();
		List<GeoJsonFeature> features = new ArrayList<GeoJsonFeature>();

		// geoPackage
		File existingGeoPackage = new File(filepath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);
		
		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(0);
			GpkgTemplate template = GpkgUtil.getGpkgTemplate(geoPackage, tableName);
			
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);

			/*
			Set<String> fieldKeySet =fieldValues.keySet();
			for (String fieldKey : fieldKeySet) {
				String fieldName = fieldKey;
				fieldValues.put(column2.getName(), column2FeatureValue);
			}
			*/
			
			FeatureResultSet cursor = featureDao.queryForAll();
			int resCount = cursor.getCount();
			System.out.println();
			//System.out.println(String.format("--->uuid: %s, count: %d  ", uuidValue, resCount));

			while ( cursor.moveToNext() ) {
				FeatureRow featureRow = cursor.getRow();
				//如果目标字段不为null或者不为empty
				Object targetFieldVal = featureRow.getValue(targetFieldName);
				if( StringUtil.isNullOrEmpty(targetFieldVal)) {
					continue;
				}
				
				//转换为gjson
				GeoJsonFeature fea = gpkgFea2Json(featureRow,template);
				features.add(fea);
			}

			cursor.close();
		}

		geoJson.setFeatures(features);
		geoJson.setType("FeatureCollection");

		geoPackage.close();

		//return JSONObject.toJSONString(geoJson);
		return geoJson;
	}
	
	/**
	 * gpkg的Feature转GeoJsonFeature
	 * 
	 * @param featureRow
	 * @param template
	 * @return
	 */
	private static GeoJsonFeature gpkgFea2Json(FeatureRow featureRow, GpkgTemplate template) {
		GeoJsonFeature fea = new GeoJsonFeature();
		
		// 1-geojson properties
		Map<String, Object> properties = new HashMap<String, Object>();
		String[] ColumnNames = featureRow.getColumnNames();
		for (int c = 0; c < ColumnNames.length; c++) {
			String columnName = ColumnNames[c];
			if (!"shape".equalsIgnoreCase(columnName)) {
				String columnType = getColumnTypeByName(template, columnName);
				String pVal = featureRow.getValue(columnName) == null ? ""
						: featureRow.getValue(columnName).toString();
				//格式化后的数据，特别是日期和时间类型
				String formatVal = pVal;
				switch(columnType.toUpperCase()) {
					case "DATE":
						if (!StringUtil.isNullOrEmpty(pVal)) {
							formatVal = JodaDateTimeUtil.formatDate(pVal);
						}
						else {
							SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
							Date date = new Date(System.currentTimeMillis());
							formatVal = formatter.format(date);					
						}
						break;
					case "DATETIME":
						if (!StringUtil.isNullOrEmpty(pVal)) {
							formatVal = JodaDateTimeUtil.formatDateTime(pVal);
						}
						else {
							SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
							Date date = new Date(System.currentTimeMillis());
							formatVal = formatter.format(date);
						}
						break;
				}
				//字段名小写
				properties.put(columnName.toLowerCase(), formatVal);
//				properties.put(columnName, formatVal);
			}
		}
		fea.setProperties(properties);

		// 2-geojson geometry
		GeoJsonGeometry geo = new GeoJsonGeometry();
		GeoPackageGeometryData geometryData = featureRow.getGeometry();
		if (geometryData != null && !geometryData.isEmpty()) {
			mil.nga.sf.Geometry geometry = geometryData.getGeometry();
			//GeometryType gType = geometry.getGeometryType();
			
			// 1-MultiPolygon
			if (geometry instanceof MultiPolygon) {
				MultiPolygon mpy = (MultiPolygon) geometry;
				List<Polygon> pys = mpy.getGeometries();
				int pysCount = pys.size();

				geo.setType("MultiPolygon");
				double[][][][] coordinates = new double[pysCount][][][];

				for (int p = 0; p < pys.size(); p++) {
					// System.out.println(String.format("------> MultiPolygon: %d ",p));
					Polygon py = pys.get(p);
					int ringCount = py.getRings().size();
					double[][][] coordinatesOfPy = new double[ringCount][][];

					// 外环
					LineString exLineStr = py.getExteriorRing();
					List<Point> exPoints = exLineStr.getPoints();
					int exPointCount = exPoints.size();
					double[][] exPointCoords = new double[exPointCount][];
					for (int j = 0; j < exPointCount; j++) {
						Point pt = exPoints.get(j);
						double[] coords = new double[2];
						coords[0] = pt.getX();
						coords[1] = pt.getY();

						exPointCoords[j] = coords;
					}
					coordinatesOfPy[0] = exPointCoords;

					// 岛宗情况
					if (ringCount > 1) {
						for (int j = 1; j < ringCount; j++) {
							// 岛宗从1开始
							LineString inLineStr = py.getInteriorRing(j);
							List<Point> inPoints = inLineStr.getPoints();

							int pointCount = inPoints.size();
							double[][] pointCoords = new double[pointCount][];
							for (int k = 0; k < pointCount; k++) {
								Point pt = inPoints.get(k);

								double[] coords = new double[2];
								coords[0] = pt.getX();
								coords[1] = pt.getY();

								pointCoords[k] = coords;
							}

							coordinatesOfPy[j] = pointCoords;
						}
					}

					coordinates[p] = coordinatesOfPy;
				}
				geo.setCoordinates(coordinates);
				fea.setGeometry(geo);
				//features.add(fea);
			} else if (geometry instanceof Polygon) {
				// 2-Polygon
				// System.out.println(String.format("------> Polygon"));
				Polygon py = (Polygon) geometry;
				int ringCount = py.getRings().size();

				geo.setType("Polygon");
				double[][][] coordinates = new double[ringCount][][];

				// 外环
				LineString exLineStr = py.getExteriorRing();
				List<Point> exPoints = exLineStr.getPoints();
				int exPointCount = exPoints.size();
				double[][] exPointCoords = new double[exPointCount][];
				for (int i = 0; i < exPointCount; i++) {
					Point pt = exPoints.get(i);
					double[] coords = new double[2];
					coords[0] = pt.getX();
					coords[1] = pt.getY();

					exPointCoords[i] = coords;
				}
				coordinates[0] = exPointCoords;

				// 岛宗情况
				if (ringCount > 1) {
					for (int j = 1; j < ringCount; j++) {
						// 岛宗从1开始
						// System.out.println(String.format("------> inter rings: %d ",j));
						LineString inLineStr = py.getInteriorRing(j);
						List<Point> inPoints = inLineStr.getPoints();

						int pointCount = inPoints.size();
						double[][] pointCoords = new double[pointCount][];
						for (int k = 0; k < pointCount; k++) {
							Point pt = inPoints.get(k);

							double[] coords = new double[2];
							coords[0] = pt.getX();
							coords[1] = pt.getY();

							pointCoords[k] = coords;
						}

						coordinates[j] = pointCoords;
					}
				}
				geo.setCoordinates(coordinates);
				fea.setGeometry(geo);
				//features.add(fea);
			}else if (geometry instanceof LineString) {
				//3-LineString
				LineString pl = (LineString) geometry;
				int pointCount = pl.getPoints().size();
				geo.setType("LineString");
				
				double[][] coordinates = new double[pointCount][];
				for (int k = 0; k < pointCount; k++) {
					Point pt = pl.getPoints().get(k);

					double[] coords = new double[2];
					coords[0] = pt.getX();
					coords[1] = pt.getY();

					coordinates[k] = coords;
				}
				geo.setCoordinates(coordinates);
				fea.setGeometry(geo);
			} else if (geometry instanceof mil.nga.sf.MultiPoint) {
				//3-LineString
				mil.nga.sf.MultiPoint mPt = (mil.nga.sf.MultiPoint) geometry;
				int pointCount = mPt.getPoints().size();
				geo.setType("MultiPoint");
				
				double[][] coordinates = new double[pointCount][];
				for (int k = 0; k < pointCount; k++) {
					Point pt = mPt.getPoints().get(k);

					double[] coords = new double[2];
					coords[0] = pt.getX();
					coords[1] = pt.getY();

					coordinates[k] = coords;
				}
				geo.setCoordinates(coordinates);
				fea.setGeometry(geo);
			}
			else if (geometry instanceof Point) {
				//4-point
				Point pt = (Point) geometry;
				geo.setType("Point");
				
				double[] coords = new double[2];
				coords[0] = pt.getX();
				coords[1] = pt.getY();
				
				geo.setCoordinates(coords);
				fea.setGeometry(geo);
			}
		}
		return fea;
	}
	
	/**
	 * gpkg要素转界址点序列
	 * 
	 * @param featureRow
	 * @return
	 */
	private static Map<String,String> gpkgFea2Jzdlist(FeatureRow featureRow) {
		//界址点坐标序列，<界址点1,jzdStr>
		Map<String,String> jzdList = new HashMap<String,String>();
		GeoPackageGeometryData geometryData = featureRow.getGeometry();
		if (geometryData != null && !geometryData.isEmpty()) {
			mil.nga.sf.Geometry geometry = geometryData.getGeometry();
			//GeometryType gType = geometry.getGeometryType();
			// MultiPolygon
			if (geometry instanceof MultiPolygon) {
				MultiPolygon mpy = (MultiPolygon) geometry;
				List<Polygon> pys = mpy.getGeometries();
				int pysCount = pys.size();
				
				for (int p = 0; p < pysCount; p++) {
					StringBuilder sb = new StringBuilder();
					int ptIndex = 0;

					String blockIndex = String.format("地块%d",p+1);
					Polygon py = pys.get(p);
					int ringCount = py.getRings().size();

					// 外环
					LineString exLineStr = py.getExteriorRing();
					List<Point> exPoints = exLineStr.getPoints();
					int exPointCount = exPoints.size();
					for (int j = 0; j < exPointCount; j++) {
						Point pt = exPoints.get(j);
						ptIndex++;

						double x = pt.getX();
						double y = pt.getY();

						String jzdrow = String.format("J%d, %d, %.3f, %.3f", ptIndex, 1, x, y );
						sb.append(jzdrow);
						sb.append(";");
					}

					// 岛宗情况
					if (ringCount > 1) {
						for (int j = 1; j < ringCount; j++) {
							// 岛宗从1开始
							LineString inLineStr = py.getInteriorRing(j);
							List<Point> inPoints = inLineStr.getPoints();

							int pointCount = inPoints.size();
							for (int k = 0; k < pointCount; k++) {
								Point pt = inPoints.get(k);
								ptIndex++;
								
								double x = pt.getX();
								double y = pt.getY();

								String jzdrow = String.format("J%d, %d, %.3f, %.3f", ptIndex, j+1, x, y );
								sb.append(jzdrow);
								sb.append(";");
							}
						}
					}
					sb.deleteCharAt(sb.length()-1);
					
					String jzdStr = sb.toString();
					jzdList.put(blockIndex, jzdStr);
				}
			} else if (geometry instanceof Polygon) {
				Polygon py = (Polygon) geometry;
				int ringCount = py.getRings().size();
				
				StringBuilder sb = new StringBuilder();
				int ptIndex = 0;
				// 外环
				LineString exLineStr = py.getExteriorRing();
				List<Point> exPoints = exLineStr.getPoints();
				int exPointCount = exPoints.size();
				for (int i = 0; i < exPointCount; i++) {
					Point pt = exPoints.get(i);
					ptIndex++;
					
					double x = pt.getX();
					double y = pt.getY();

					String jzdrow = String.format("J%d, %d, %.3f, %.3f", ptIndex, 1, x, y );
					sb.append(jzdrow);
					sb.append(";");
				}

				// 岛宗情况
				if (ringCount > 1) {
					for (int j = 1; j < ringCount; j++) {
						// 岛宗从1开始
						LineString inLineStr = py.getInteriorRing(j);
						List<Point> inPoints = inLineStr.getPoints();

						int pointCount = inPoints.size();
						for (int k = 0; k < pointCount; k++) {
							Point pt = inPoints.get(k);
							ptIndex++;
							
							double x = pt.getX();
							double y = pt.getY();

							String jzdrow = String.format("J%d, %d, %.3f, %.3f", ptIndex, j+1, x, y );
							sb.append(jzdrow);
							sb.append(";");
						}
					}
				}
				
				sb.deleteCharAt(sb.length()-1);
				
				String jzdStr = sb.toString();
				jzdList.put("地块1", jzdStr);
			}
			else if (geometry instanceof LineString) {
				LineString pl = (LineString) geometry;

				StringBuilder sb = new StringBuilder();
				int ptIndex = 0;
				
				//环
				List<Point> exPoints = pl.getPoints();
				int exPointCount = exPoints.size();
				for (int i = 0; i < exPointCount; i++) {
					Point pt = exPoints.get(i);
					ptIndex++;
					
					double x = pt.getX();
					double y = pt.getY();

					String jzdrow = String.format("J%d, %d, %.3f, %.3f", ptIndex, 1, x, y );
					sb.append(jzdrow);
					sb.append(";");
				}
				
				sb.deleteCharAt(sb.length()-1);
				
				String jzdStr = sb.toString();
				jzdList.put("地块1", jzdStr);
			}
		}
		
		return jzdList;
	}
	
	
	/**
	 * updateGpkgFeature 更新一个gpkg的一行，即featureRow，不包含UUID字段
	 * 
	 * @param template     gpkg模板
	 * @param featureRow   待更新Gpkg文件的FeatureRow 
	 * @param newGeom        新图形GeoJsonGeometry
	 * @param newProperties  新属性集合Map<String, Object>        
	 * @param bUpdateGeometry  是否更新图形
	 * @throws ParseException
	 * @throws java.text.ParseException
	 */
	private static void updateGpkgFeature(GpkgTemplate template, FeatureRow featureRow, GeoJsonGeometry newGeom, Map<String, Object> newProperties, boolean bUpdateGeometry)
			throws ParseException, java.text.ParseException {
		long srsId = template.getSrsId();
		// String[] ColumnNames = featureRow.getColumnNames();
		FeatureColumns feaColumns = featureRow.getColumns();		
		for (FeatureColumn featureColumn :  feaColumns.getColumns() ) {
			String columnName = featureColumn.getName();
			// int columnIndex = featureColumn.getIndex();
			
			if (featureColumn.isPrimaryKey()) {
				//主键字段
				continue;
			}
			
			if (featureColumn.isGeometry()) {
				// 1-图形 
				if (bUpdateGeometry == true) {
					//是否成功
					boolean updateGeometry = true;
					String geomType = newGeom.getType();
					String geomStr = JSONObject.toJSONString(newGeom);
					//System.out.println(String.format("geomType: %s, geomStr: %s ", geomType, geomStr));
					String wkt = json2Wkt(geomStr);
					//System.out.println("wkt: " + wkt);

					GeoPackageGeometryData geomData = new GeoPackageGeometryData(srsId);
					switch (geomType.toLowerCase()) {
					case "multipolygon":
						MultiPolygon mp = NFGeometryWKTUtil.createMulPolygonByWKT(wkt);
						// 测试
						/*
						List<Polygon> polygons = mp.getPolygons();
						int numOfPolygon = polygons.size();
						for (int n = 0; n < numOfPolygon; n++) {
							Polygon p = polygons.get(n);
							List<LineString> rings = p.getRings();
							for (int m = 0; m < rings.size(); m++) {
								LineString ring = rings.get(m);
								List<Point> pts = ring.getPoints();
								for (int k = 0; k < pts.size(); k++) {
									Point coord = pts.get(k);
									System.out.println(String.format("%d---%d---%d, %.3f, %.3f", n, m, k, coord.getX(),
											coord.getY()));
								}
							}
						}
						*/
						geomData.setGeometry(mp);
						break;

					case "polygon":
						Polygon py = NFGeometryWKTUtil.createPolygonByWKT(wkt);
						geomData.setGeometry(py);
						break;
					case "polyline":
					case "linestring":
						LineString polyline = NFGeometryWKTUtil.createLineByWKT(wkt);
						geomData.setGeometry(polyline);
						break;
					case "point":
						Point point = NFGeometryWKTUtil.createPointByWKT(wkt);
						geomData.setGeometry(point);
						break;
					default:
						updateGeometry = false;
						break;
					}

					if (updateGeometry) {
						featureRow.setGeometry(geomData);
					}
				}
			} else {
				// 保证objectid、uuid和shape等字段属性不发生变化
				if (!"shape".equalsIgnoreCase(columnName) && !gpkg_uuid.equalsIgnoreCase(columnName)) {
					String oldVal = featureRow.getValue(columnName) == null ? ""
							: featureRow.getValue(columnName).toString();
					Object proVal = newProperties.get(columnName);
					// 若新值为null或者值没有变化
					if (proVal == null || oldVal.equals(proVal)) {
						continue;
					}

					// 根据模板判断字段类型
					String columnType = getColumnTypeByName(template, columnName);
					
					//更新gpkg列
					setFeatureColumn(featureRow, columnName, columnType, proVal);
				}
			}
		}
	}
	
	/**
	 * updateGpkgFeature 更新一个gpkg的一行，即featureRow，包含UUID
	 * 
	 * @param template     gpkg模板
	 * @param featureRow   待更新Gpkg文件的FeatureRow 
	 * @param newGeom        新图形GeoJsonGeometry
	 * @param newProperties  新属性集合Map<String, Object>        
	 * @param bUpdateGeometry  是否更新图形
	 * @throws ParseException
	 * @throws java.text.ParseException
	 */
	private static void updateGpkgFeature2(GpkgTemplate template, 
			FeatureRow featureRow, 
			GeoJsonGeometry newGeom, 
			Map<String, Object> newProperties, boolean bUpdateGeometry)
			throws ParseException, java.text.ParseException {
		long srsId = template.getSrsId();
		
		FeatureColumns feaColumns = featureRow.getColumns();		
		for (FeatureColumn featureColumn :  feaColumns.getColumns() ) {
			//int columnIndex = featureColumn.getIndex();
			//String columnName = featureColumn.getName();
			String columnName = featureColumn.getName().toLowerCase();//吕改

			if (featureColumn.isPrimaryKey()) {
				//主键字段
				continue;
			}
			
			if (featureColumn.isGeometry()) {
				// 1-图形 
				if (bUpdateGeometry == true) {
					//是否成功
					boolean updateGeometry = true;
					String geomType = newGeom.getType();
					String geomStr = JSONObject.toJSONString(newGeom);
					//System.out.println(String.format("geomType: %s, geomStr: %s ", geomType, geomStr));
					String wkt = json2Wkt(geomStr);
					//System.out.println("wkt: " + wkt);

					GeoPackageGeometryData geomData = new GeoPackageGeometryData(srsId);
					switch (geomType.toLowerCase()) {
					case "multipolygon":
						MultiPolygon mp = NFGeometryWKTUtil.createMulPolygonByWKT(wkt);

						geomData.setGeometry(mp);
						break;

					case "polygon":
						Polygon py = NFGeometryWKTUtil.createPolygonByWKT(wkt);
						geomData.setGeometry(py);
						break;
					case "polyline":
					case "linestring":
						LineString polyline = NFGeometryWKTUtil.createLineByWKT(wkt);
						geomData.setGeometry(polyline);
						break;
					case "point":
						Point point = NFGeometryWKTUtil.createPointByWKT(wkt);
						geomData.setGeometry(point);
						break;
					default:
						updateGeometry = false;
						break;
					}

					if (updateGeometry) {
						featureRow.setGeometry(geomData);
					}
				}
			} else {
				//update properties
				//保证objectid和shape等字段属性不发生变化
				if (!"shape".equalsIgnoreCase(columnName) ) {
					String oldVal = featureRow.getValue(columnName) == null ? ""
							: featureRow.getValue(columnName).toString();
					Object proVal = newProperties.get(columnName);
					// 若新值为null或者值没有变化
					if (proVal == null || oldVal.equals(proVal)) {
						continue;
					}

					// 根据模板判断字段类型
					String columnType = getColumnTypeByName(template, columnName);
					
					//更新gpkg列
					setFeatureColumn(featureRow, columnName, columnType, proVal);
				}
			}
		}
	}
	
	private static void updateGpkgFeature3(GpkgTemplate template, FeatureRow featureRow, GeoJsonGeometry newGeom, Map<String, Object> newProperties, boolean bUpdateGeometry)
			throws ParseException, java.text.ParseException {
		long srsId = template.getSrsId();
		FeatureColumns feaColumns = featureRow.getColumns();		
		for (FeatureColumn featureColumn :  feaColumns.getColumns() ) {
			// int columnIndex = featureColumn.getIndex();
            // String columnName = featureColumn.getName();
			//字段名全部转为小写
			String columnName = featureColumn.getName().toLowerCase();//吕改

			if (featureColumn.isPrimaryKey()) {
				//主键字段
				continue;
			}
			
			if (featureColumn.isGeometry()) {
				// 1-图形 
				if (bUpdateGeometry == true) {
					//是否成功
					boolean updateGeometry = true;
					String geomType = newGeom.getType();
					String geomStr = JSONObject.toJSONString(newGeom);
					//System.out.println(String.format("geomType: %s, geomStr: %s ", geomType, geomStr));
					String wkt = json2Wkt(geomStr);
					//System.out.println("wkt: " + wkt);

					GeoPackageGeometryData geomData = new GeoPackageGeometryData(srsId);
					switch (geomType.toLowerCase()) {
					case "multipolygon":
						MultiPolygon mp = NFGeometryWKTUtil.createMulPolygonByWKT(wkt);
						geomData.setGeometry(mp);
						break;
					case "polygon":
						Polygon py = NFGeometryWKTUtil.createPolygonByWKT(wkt);
						geomData.setGeometry(py);
						break;
					case "polyline":
					case "linestring":
						LineString polyline = NFGeometryWKTUtil.createLineByWKT(wkt);
						geomData.setGeometry(polyline);
						break;
					case "point":
						Point point = NFGeometryWKTUtil.createPointByWKT(wkt);
						geomData.setGeometry(point);
						break;
					default:
						updateGeometry = false;
						break;
					}

					if (updateGeometry) {
						featureRow.setGeometry(geomData);
					}
				}
			} else {
				//update properties
				//保证objectid和shape等字段属性不发生变化
				if (!"shape".equalsIgnoreCase(columnName) ) {
					String oldVal = featureRow.getValue(columnName) == null ? ""
							: featureRow.getValue(columnName).toString();
					Object proVal = newProperties.get(columnName);
					
					// 根据模板判断字段类型
					String columnType = getColumnTypeByName(template, columnName);
					if(StringUtil.isNullOrEmpty(proVal)) {
						if( "DOUBLE".equalsIgnoreCase(columnType) || "FLOAT".equalsIgnoreCase(columnType)) {
							proVal = 0.0;
						}else if("INTEGER".equalsIgnoreCase(columnType)|| "INT".equalsIgnoreCase(columnType)) {
							proVal = 0;
						}else if("TEXT".equalsIgnoreCase(columnType) || "STRING".equalsIgnoreCase(columnType)) {
							proVal = "";
						}else if("DATE".equalsIgnoreCase(columnType) ||"DATETIME".equalsIgnoreCase(columnType)) {
							proVal = "";
						}
					}
					//更新gpkg列
					setFeatureColumn(featureRow, columnName, columnType, proVal);
				}
			}
		}
	}
	
	
	/**
	 * setFeatureColumn 设置gpkg中一条记录中某列的值
	 * 
	 * @param featureRow  行
	 * @param columnName  列名
	 * @param columnType  列数据类型
	 * @param proVal    值
	 * 
	 * @throws java.text.ParseException
	 */
	private static void setFeatureColumn(FeatureRow featureRow,String columnName,String columnType,Object proVal) throws java.text.ParseException {
		switch (columnType.toUpperCase()) {	
			case "INT":
			case "INTEGER":
				int inewVal = -1;
				if (!StringUtil.isNullOrEmpty(proVal)) {
					inewVal = Integer.parseInt(String.valueOf(proVal));
				}
				featureRow.setValue(columnName, inewVal);
				break;
			case "STRING":
			case "TEXT":
				featureRow.setValue(columnName, String.valueOf(proVal));
				break;
			case "FLOAT":
			case "DOUBLE":
				double dnewVal = 0.0;
				if (!StringUtil.isNullOrEmpty(String.valueOf(proVal))) {
					dnewVal = Double.parseDouble(String.valueOf(proVal));
				}
				featureRow.setValue(columnName, dnewVal);
				break;
			case "DATE":
				Date dateVal = null;
				if (!StringUtil.isNullOrEmpty(proVal)) {
					String dateStr = String.valueOf(proVal);
					dateVal = JodaDateTimeUtil.strToDate(dateStr);
				}
				featureRow.setValue(columnName, dateVal);
				break;
			case "DATETIME":
				Date date = null;
				if (!StringUtil.isNullOrEmpty(proVal)) {
					String dateStr = String.valueOf(proVal);
					date = JodaDateTimeUtil.strToDate(dateStr);
				}
				featureRow.setValue(columnName, date);
				break;
			default: 
		        System.out.println("setFeatureColumn-->columnType is unknown!"); 
		        break;
		}
	}

	private static ByteBuffer convertStringToByte(String content,String encoding){
		try {
			//String encoding="GBK"
			return ByteBuffer.wrap(content.getBytes(encoding));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return null;
		}
	}
	private static String byteBuff2Str(ByteBuffer bb, String encoding) {  
		//encoding="utf-8"
        Charset charset = Charset.forName(encoding);
        return charset.decode(bb).toString();   
	} 
	
	/**
	 * saveToGpkgDB 提交到最终库GPKG
	 * 
	 * @param filepath gpkg物理文件路径 例如E:\temp\gpkg\lv\lv.gpkg
	 * @param gjsonStr 新数据的geojson字符串( GeoJson对象序列化结果)
	 * @param epsg     坐标投影espg 
	 * 
	 * @return 返回插入成功的Uuid Set<>集合
	 * 
	 * @throws IOException
	 * @throws SQLException
	 * @throws ParseException
	 */
	public static Set<String> saveToGpkgDB(String filepath, GeoJson geoJson, 
			String collectId) throws IOException, SQLException, ParseException {
		Set<String> sucUuidSet = new HashSet<String>();
		//是否更新图形
		boolean bUpdateGeometry = true;
		
		List<GeoJsonFeature> feaList = geoJson.getFeatures();
		// geoPackage
		File existingGeoPackage = new File(filepath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);
		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(0);
			GpkgTemplate template = GpkgUtil.getGpkgTemplate(geoPackage, tableName);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			featureDao.beginTransaction();
			for (int i = 0; i < feaList.size(); i++) {
				GeoJsonFeature geoFea = feaList.get(i);

				Map<String, Object> newProperties = geoFea.getProperties();
				String uuidValue = newProperties.get(gpkg_uuid).toString();
				//要素游标
				FeatureResultSet cursor = featureDao.queryForAll();
				int count = cursor.getCount();
				System.out.println("origin count: " + count);

				//String objectId = featureDao.getIdColumnName();
				FeatureRow featureRow = featureDao.newRow();
				GeoJsonGeometry newGeom = geoFea.getGeometry();
				
				long rowId=0;
				
				try {
					//更新FeatureRow
					updateGpkgFeature(template, featureRow, newGeom, newProperties, bUpdateGeometry);
					rowId = featureDao.insert(featureRow);
					featureDao.commit();
					
				} catch (java.text.ParseException e) {
					e.printStackTrace();
				}
				if (rowId > 0) {
					sucUuidSet.add(uuidValue);
				}
				cursor.close();
			}

			featureDao.endTransaction();
		}
		
		geoPackage.close();
		return sucUuidSet;
	}
	
	/**
	 * gpkg2Shp 负责将一个Gpkg文件下的第一个表tableName转换为一个shp文件
	 * 
	 * @param gpkgPath  Gpkg文件路径
	 * @param shpPath   shp文件路径，如果存在则替换
	 * @param encoding  默认是GBK
	 * 
	 * @return
	 * @throws IOException
	 * @throws FactoryException
	 * @throws ParseException 
	 */
	public static boolean gpkg2Shp(String gpkgPath,String shpPath,String encoding) throws IOException, FactoryException, ParseException {
		boolean bSuccess=false;
		// 创建shape文件对象
		if (StringUtil.isNullOrEmpty(encoding)) {
			encoding = "GBK";
		}
		//判断模板文件
		String gpkgfilePath = FileUtil.getPathOfDiskFile(gpkgPath);
		String templatefilePath = gpkgfilePath+File.separator+"template0.json";
		File templatefile = new File(templatefilePath);		
		if( !templatefile.exists() ) {
			//创建模板到文件中
			List<GpkgTemplate> templates = GpkgUtil.getGpkgTemplates(gpkgPath);
			if(templates.size()>0) {
				saveGpkgTemplateToFile(templates.get(0), templatefilePath);
			}
		}
		// geoPackage
		File gpkgFile = new File(gpkgPath);
		GeoPackage geoPackage = GeoPackageManager.open(gpkgFile);
		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(0);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			FeatureResultSet cursor = featureDao.queryForAll();
			int resCount = cursor.getCount();
			System.out.println();
			//System.out.println(String.format("--->uuid: %s, count: %d  ", uuidValue, resCount));
			if(resCount==0 ) {
				return false;
			}
			
			String geoColumnName = featureDao.getGeometryColumnName();
			String pkidColumnName =featureDao.getIdColumnName();
			//gpkg字段模板
			GpkgTemplate template = loadGpkgTemplate(templatefilePath);
			GeometryType geometryType = featureDao.getGeometryType();
			
			long epsg = template.getSrsId();
			String wkt = CrsUtil.getWKT(String.valueOf(epsg));
			List<FieldInfo> fieldInfos = template.getFieldInfos();
			
			// 创建shape文件对象
			File newshpfile = new File(shpPath);
			if(newshpfile.exists()) {
				//如果存在，则删除
				newshpfile.delete();
			}
			Map<String, Serializable> params = new HashMap<String, Serializable>();
			//params.put("url", newshpfile.toURI().toURL());
			params.put(ShapefileDataStoreFactory.URLP.key, newshpfile.toURI().toURL());
			ShapefileDataStore sfds = (ShapefileDataStore)new ShapefileDataStoreFactory().createNewDataStore(params);
			Charset charset = Charset.forName(encoding);
			sfds.setCharset(charset);	// 定义字符集
			
			// 定义坐标系
	        SimpleFeatureTypeBuilder sftb = new SimpleFeatureTypeBuilder();
	        CoordinateReferenceSystem crs = CRS.parseWKT(wkt);
	        sftb.setCRS(crs);
	        sftb.setName("shapefile");
	        // 定义几何类型，注意这里的类型可能会有误导，建议加上包全路径
	        String geoTypeName = geometryType.getName();
	        if ("MultiPolygon".equalsIgnoreCase(geoTypeName)) {
	        	sftb.add("the_geom", com.vividsolutions.jts.geom.MultiPolygon.class);
	        }else if ("Polygon".equalsIgnoreCase(geoTypeName)) {
	        	sftb.add("the_geom", com.vividsolutions.jts.geom.Polygon.class);
	        } else if ("LineString".equalsIgnoreCase(geoTypeName) || "Polyline".equalsIgnoreCase(geoTypeName)) {
	        	sftb.add("the_geom", com.vividsolutions.jts.geom.LineString.class);
	        } else if ("Point".equalsIgnoreCase(geoTypeName)) {
	        	sftb.add("the_geom", com.vividsolutions.jts.geom.Point.class);
	        }
	        
			//定义shp属性字段
			int maxlengthOfField = 11;
			
			Iterator<FieldInfo> fieldIter = fieldInfos.iterator();
			//字段名的映射
			Map<String,String> newfieldMappings = new HashMap<String,String>();
			while (fieldIter.hasNext()) {
				FieldInfo f = fieldIter.next();				
				String fn = f.getName().toString();
				String ft = f.getType().toString();
				//字段长度截取
				String newFn = fn;
				int len = fn.getBytes(Charset.forName("GBK")).length;
				if(len > maxlengthOfField) {
					newFn = StringUtil.slice(fn, maxlengthOfField, "GBK");
				}
				if ( !(gpkg_pkColumnId.equalsIgnoreCase(fn) || geoColumnName.equalsIgnoreCase(fn) || pkidColumnName.equalsIgnoreCase(fn))) {
					if (ft.equalsIgnoreCase("INT") || ft.equalsIgnoreCase("INTEGER") || ft.equalsIgnoreCase("esriFieldTypeInteger") || ft.equalsIgnoreCase("esriFieldTypeOID")) {
						sftb.add(newFn, Integer.class);
					} else if (ft.equalsIgnoreCase("long") || ft.equalsIgnoreCase("esriFieldTypeLong")) {
		        		sftb.add(newFn, Long.class);
					} else if (ft.equalsIgnoreCase("DOUBLE") || ft.equalsIgnoreCase("esriFieldTypeDouble")) {
						sftb.add(newFn, Double.class);
					} else if (ft.equalsIgnoreCase("FLOAT")) {
						sftb.add(newFn, Float.class);
					}
					else if (ft.equalsIgnoreCase("DATE")) {
						sftb.add(newFn, Date.class);
					} 
					else if (ft.equalsIgnoreCase("DATETIME")) {
						sftb.add(newFn, Date.class);
					}
					else if (ft.equalsIgnoreCase("TEXT") || ft.equalsIgnoreCase("STRING")) {
						sftb.add(newFn, String.class);
					} else {
						sftb.add(newFn, String.class);
					}
					
					newfieldMappings.put(fn, newFn);
				}
			}
			sfds.createSchema(sftb.buildFeatureType());

			FeatureWriter<SimpleFeatureType, SimpleFeature> shpwriter = sfds.getFeatureWriter(sfds.getTypeNames()[0], Transaction.AUTO_COMMIT);	
			
			//遍历gpkg所有要素
			while (cursor.moveToNext()) {								
				FeatureRow featureRow = cursor.getRow();
				//geometryData
				GeoPackageGeometryData geometryData = featureRow.getGeometry();				
				if (geometryData == null || geometryData.isEmpty()) {
					continue;
				}
				
				mil.nga.sf.Geometry geometry = geometryData.getGeometry();
				//将nga.sf.Geometry转换为Wkt格式的字符表示
				String wkb = NFGeometryWKTUtil.nfGeom2Wkt(geometry);
				//读取wkt构建jts格式的图形，后续将写入图形到shp的simpleFeature中
				Geometry jtsgeometry=null;
				if( "MULTIPOLYGON".equalsIgnoreCase( geometryType.getName() ) ) {
					com.vividsolutions.jts.geom.MultiPolygon mpy = JTSGeometryWKTUtil.createMulPolygonByWKT(wkb);
					jtsgeometry = mpy;
				}else if( "POLYGON".equalsIgnoreCase( geometryType.getName() ) ) {
					com.vividsolutions.jts.geom.Polygon py = JTSGeometryWKTUtil.createPolygonByWKT(wkb);
					jtsgeometry = py;
				}else if("LineString".equalsIgnoreCase(geometryType.getName()) || "Polyline".equalsIgnoreCase(geometryType.getName())) {
					com.vividsolutions.jts.geom.LineString pl = JTSGeometryWKTUtil.createLineByWKT(wkb);
					jtsgeometry = pl;
				}else if("Point".equalsIgnoreCase(geometryType.getName())) {
					com.vividsolutions.jts.geom.Point pt = JTSGeometryWKTUtil.createPointByWKT(wkb);
					jtsgeometry = pt;
				}else {
					continue;
				}
				
				SimpleFeature feature = shpwriter.next();
				
				//1-图形
				feature.setAttribute("the_geom", jtsgeometry);
				
				//2-属性
				Set<String> fnSet = newfieldMappings.keySet();
				Iterator<String> fnIter= fnSet.iterator();
				while (fnIter.hasNext()) {
					String fieldName = fnIter.next();
					String newFieldName = newfieldMappings.get(fieldName);
					//原gpkg文件中的字段值
					String proVal = featureRow.getValue(fieldName) == null ? ""
							: featureRow.getValue(fieldName).toString();
					
					//原gpkg文件中的字段类型
					String columnType = getColumnTypeByName(template, fieldName);
					switch (columnType.toUpperCase()) {
					case "INT":
					case "INTEGER":
						int inewVal = -1;
						if (!StringUtil.isNullOrEmpty(proVal)) {
							inewVal = Integer.parseInt(String.valueOf(proVal));
							feature.setAttribute(newFieldName, inewVal);
						}
						break;
					case "STRING":
					case "TEXT":
						String strVal = "";
						// UUID
						if (gpkg_uuid.equalsIgnoreCase(fieldName) && StringUtil.isNullOrEmpty(proVal)) {
							strVal = UUID.randomUUID().toString();
							feature.setAttribute(newFieldName, strVal);
						} else {
							if( !StringUtil.isNullOrEmpty(proVal)) {
								strVal = String.valueOf(proVal);
								feature.setAttribute(newFieldName, strVal);
							}
						}
						break;
					case "FLOAT":
					case "DOUBLE":
						double dnewVal = 0.0;
						if ( !StringUtil.isNullOrEmpty(proVal)) {
							dnewVal = Double.parseDouble(String.valueOf(proVal));
							feature.setAttribute(newFieldName, dnewVal);
						}
						break;
					case "DATE":
						Date dateVal = null;
						if (!StringUtil.isNullOrEmpty(proVal)) {
							dateVal = JodaDateTimeUtil.strToDate(String.valueOf(proVal));
							
							feature.setAttribute(newFieldName, dateVal);
						}
						break;
					case "DATETIME":
						String dTimeValStr = null;
						if (!StringUtil.isNullOrEmpty(proVal)) {
							//其实这里可以设置为date
							dTimeValStr = JodaDateTimeUtil.formatDateTime(String.valueOf(proVal));
							
							feature.setAttribute(newFieldName, dTimeValStr);
						}
						break;
					}
				}
		        shpwriter.write();
			}
			shpwriter.close();
			sfds.dispose();
			cursor.close();
			
			//覆盖prj文件
			String fname= FileUtil.getFileNameWithNoPathAndExtension(shpPath);
			String fPath = FileUtil.getPathOfDiskFile(shpPath);
			String prjFile = fPath+fname+".prj";
			FileUtil.writeFile(wkt, prjFile);
			
			bSuccess = true;
		}
		
		geoPackage.close();
		
		return bSuccess;
	}

	/**
	 * gpkg转shp
	 * 
	 * @param gpkgPath    输入gpkg文件路径
	 * @param shpPath     输出shp文件路径
	 * @param encoding    字符编码,默认为GBK
	 * @param epsgTarget  输出坐标投影的espg
	 * @return
	 * @throws IOException
	 * @throws FactoryException
	 * @throws ParseException 
	 */
	public static boolean gpkg2Shp(String gpkgPath,String shpPath,String encoding, long epsgTarget) throws IOException, FactoryException, ParseException {
		boolean bSuccess=false;
		// 创建shape文件对象
		if (StringUtil.isNullOrEmpty(encoding)) {
			encoding = "GBK";
		}
		//判断模板文件
		String gpkgfilePath = FileUtil.getPathOfDiskFile(gpkgPath);
		String templatefilePath = gpkgfilePath+File.separator+"template0.json";
		File templatefile = new File(templatefilePath);		
		if( !templatefile.exists() ) {
			//创建模板到文件中
			List<GpkgTemplate> templates = GpkgUtil.getGpkgTemplates(gpkgPath);
			if(templates.size()>0) {
				saveGpkgTemplateToFile(templates.get(0), templatefilePath);
			}
		}
		// geoPackage
		File gpkgFile = new File(gpkgPath);
		GeoPackage geoPackage = GeoPackageManager.open(gpkgFile);
		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(0);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			FeatureResultSet cursor = featureDao.queryForAll();
			int resCount = cursor.getCount();
			System.out.println();
			//System.out.println(String.format("--->uuid: %s, count: %d  ", uuidValue, resCount));
			if(resCount==0 ) {
				return false;
			}
			
			String geoColumnName = featureDao.getGeometryColumnName();
			String pkidColumnName =featureDao.getIdColumnName();
			//gpkg字段模板
			GpkgTemplate template = loadGpkgTemplate(templatefilePath);
			GeometryType geometryType = featureDao.getGeometryType();
			
			long epsg = template.getSrsId();//这个epsg是wkid的一种
			//注意这里要改为新的epsg参数才行
			String wktSource = CrsUtil.getWKT(String.valueOf(epsg));
			String wktTarget = CrsUtil.getWKT(String.valueOf(epsgTarget));
			
			List<FieldInfo> fieldInfos = template.getFieldInfos();
			
			// 创建shape文件对象
			File newshpfile = new File(shpPath);
			if(newshpfile.exists()) {
				//如果存在，则删除
				newshpfile.delete();
			}
			Map<String, Serializable> params = new HashMap<String, Serializable>();
			//params.put("url", newshpfile.toURI().toURL());
			params.put(ShapefileDataStoreFactory.URLP.key, newshpfile.toURI().toURL());
			ShapefileDataStore sfds = (ShapefileDataStore)new ShapefileDataStoreFactory().createNewDataStore(params);
			Charset charset = Charset.forName(encoding);
			sfds.setCharset(charset);	//定义字符集
			
			// 定义坐标系
	        SimpleFeatureTypeBuilder sftb = new SimpleFeatureTypeBuilder();
	        CoordinateReferenceSystem crs = CRS.parseWKT(wktTarget);
	        sftb.setCRS(crs);
	        sftb.setName("shapefile");
	        // 定义几何类型，注意这里的类型可能会有误导，建议加上包全路径
	        String geoTypeName = geometryType.getName();
	        if ("MultiPolygon".equalsIgnoreCase(geoTypeName)) {
	        	sftb.add("the_geom", com.vividsolutions.jts.geom.MultiPolygon.class);
	        }else if ("Polygon".equalsIgnoreCase(geoTypeName)) {
	        	sftb.add("the_geom", com.vividsolutions.jts.geom.Polygon.class);
	        } else if ("LineString".equalsIgnoreCase(geoTypeName) || "Polyline".equalsIgnoreCase(geoTypeName)) {
	        	sftb.add("the_geom", com.vividsolutions.jts.geom.LineString.class);
	        } else if ("Point".equalsIgnoreCase(geoTypeName)) {
	        	sftb.add("the_geom", com.vividsolutions.jts.geom.Point.class);
	        }
	       
			//定义shp属性字段
			int maxlengthOfField = 11;
			
			Iterator<FieldInfo> fieldIter = fieldInfos.iterator();
			//字段名的映射
			Map<String,String> newfieldMappings = new HashMap<String,String>();
			while (fieldIter.hasNext()) {
				FieldInfo f = fieldIter.next();				
				String fn = f.getName().toString();
				String ft = f.getType().toString();
				//字段长度截取
				String newFn = fn;
				int len = fn.getBytes(Charset.forName("GBK")).length;
				if(len > maxlengthOfField) {
					newFn = StringUtil.slice(fn, maxlengthOfField, "GBK");
				}
				if ( !(gpkg_pkColumnId.equalsIgnoreCase(fn) || geoColumnName.equalsIgnoreCase(fn) || pkidColumnName.equalsIgnoreCase(fn))) {
					if (ft.equalsIgnoreCase("INT") || ft.equalsIgnoreCase("INTEGER") || ft.equalsIgnoreCase("esriFieldTypeInteger") || ft.equalsIgnoreCase("esriFieldTypeOID")) {
						sftb.add(newFn, Integer.class);
					} else if (ft.equalsIgnoreCase("long") || ft.equalsIgnoreCase("esriFieldTypeLong")) {
		        		sftb.add(newFn, Long.class);
					} else if (ft.equalsIgnoreCase("DOUBLE") || ft.equalsIgnoreCase("esriFieldTypeDouble")) {
						sftb.add(newFn, Double.class);
					} else if (ft.equalsIgnoreCase("FLOAT")) {
						sftb.add(newFn, Float.class);
					}
					else if (ft.equalsIgnoreCase("DATE")) {
						sftb.add(newFn, Date.class);
					} 
					else if (ft.equalsIgnoreCase("DATETIME")) {
						sftb.add(newFn, Date.class);
					}
					else if (ft.equalsIgnoreCase("TEXT") || ft.equalsIgnoreCase("STRING")) {
						sftb.add(newFn, String.class);
					} else {
						sftb.add(newFn, String.class);
					}
					
					newfieldMappings.put(fn, newFn);
				}
			}
			sfds.createSchema(sftb.buildFeatureType());

			FeatureWriter<SimpleFeatureType, SimpleFeature> shpwriter = sfds.getFeatureWriter(sfds.getTypeNames()[0], Transaction.AUTO_COMMIT);	
			
			//遍历gpkg所有要素
			while (cursor.moveToNext()) {								
				FeatureRow featureRow = cursor.getRow();
				//geometryData
				GeoPackageGeometryData geometryData = featureRow.getGeometry();				
				if (geometryData == null || geometryData.isEmpty()) {
					continue;
				}
				
				mil.nga.sf.Geometry geometry = geometryData.getGeometry();
				//将nga.sf.Geometry转换为Wkt/wkb格式的字符表示
				String wkb = NFGeometryWKTUtil.nfGeom2Wkt(geometry);
				
				//读取wkt构建jts格式的图形，后续将写入图形到shp的simpleFeature中
				Geometry jtsgeometry = null;
				if( "MULTIPOLYGON".equalsIgnoreCase( geometryType.getName() ) ) {
					com.vividsolutions.jts.geom.MultiPolygon mpy = JTSGeometryWKTUtil.createMulPolygonByWKT(wkb);
					jtsgeometry = mpy;
				}else if( "POLYGON".equalsIgnoreCase( geometryType.getName() ) ) {
					com.vividsolutions.jts.geom.Polygon py = JTSGeometryWKTUtil.createPolygonByWKT(wkb);
					jtsgeometry = py;
				}else if("LineString".equalsIgnoreCase(geometryType.getName()) || "Polyline".equalsIgnoreCase(geometryType.getName())) {
					com.vividsolutions.jts.geom.LineString pl = JTSGeometryWKTUtil.createLineByWKT(wkb);
					jtsgeometry = pl;
				}else if("Point".equalsIgnoreCase(geometryType.getName())) {
					com.vividsolutions.jts.geom.Point pt = JTSGeometryWKTUtil.createPointByWKT(wkb);
					jtsgeometry = pt;
				}else {
					continue;
				}
				
				//投影转换
				Geometry newjtsGeometry = GpkgUtil.geomPrjTransform2(jtsgeometry,
						wktSource,
						wktTarget );
				
				SimpleFeature feature = shpwriter.next();
				
				//1-图形
				feature.setAttribute("the_geom", newjtsGeometry);
				
				//2-属性
				Set<String> fnSet = newfieldMappings.keySet();
				Iterator<String> fnIter= fnSet.iterator();
				while (fnIter.hasNext()) {
					String fieldName = fnIter.next();
					String newFieldName = newfieldMappings.get(fieldName);
					//原gpkg文件中的字段值
					String proVal = featureRow.getValue(fieldName) == null ? ""
							: featureRow.getValue(fieldName).toString();
					
					//原gpkg文件中的字段类型
					String columnType = getColumnTypeByName(template, fieldName);
					switch (columnType.toUpperCase()) {
					case "INT":
					case "INTEGER":
						int inewVal = -1;
						if (!StringUtil.isNullOrEmpty(proVal)) {
							inewVal = Integer.parseInt(String.valueOf(proVal));
							feature.setAttribute(newFieldName, inewVal);
						}
						break;
					case "STRING":
					case "TEXT":
						String strVal = "";
						// UUID
						if (gpkg_uuid.equalsIgnoreCase(fieldName) && StringUtil.isNullOrEmpty(proVal)) {
							strVal = UUID.randomUUID().toString();
							feature.setAttribute(newFieldName, strVal);
						} else {
							if( !StringUtil.isNullOrEmpty(proVal)) {
								strVal = String.valueOf(proVal);
								System.out.println("newFieldName, strVal：" + newFieldName + strVal);
								if(newFieldName != null) {
									feature.setAttribute(newFieldName, strVal);
								}								
							}
						}
						break;
					case "FLOAT":
					case "REAL":
					case "DOUBLE":
						double dnewVal = 0.0;
						if ( !StringUtil.isNullOrEmpty(proVal)) {
							dnewVal = Double.parseDouble(String.valueOf(proVal));
							feature.setAttribute(newFieldName, dnewVal);
						}
						break;
					case "DATE":
						Date dateVal = null;
						if (!StringUtil.isNullOrEmpty(proVal)) {
							dateVal = JodaDateTimeUtil.strToDate(String.valueOf(proVal));
							
							feature.setAttribute(newFieldName, dateVal);
						}
						break;
					case "DATETIME":
						String dTimeValStr = null;
						if (!StringUtil.isNullOrEmpty(proVal)) {
							//其实这里可以设置为date
							dTimeValStr = JodaDateTimeUtil.formatDateTime(String.valueOf(proVal));
							
							feature.setAttribute(newFieldName, dTimeValStr);
						}
						break;
					}
				}
		        shpwriter.write();
			}
			shpwriter.close();
			sfds.dispose();
			cursor.close();
			
			//覆盖prj文件
			String fname = FileUtil.getFileNameWithNoPathAndExtension(shpPath);
			String fPath = FileUtil.getPathOfDiskFile(shpPath);
			String prjFile = fPath+fname+".prj";
			FileUtil.writeFile(wktTarget, prjFile);
			
			bSuccess = true;
		}
		
		geoPackage.close();
		
		return bSuccess;
	}

	/**
	 * 投影转换-epsg
	 * 
	 * @param geom
	 * @param epsgSource
	 * @param epsgTarget
	 * @return
	 */
	public static Geometry geomPrjTransform(Geometry geom, long epsgSource, long epsgTarget){
		Geometry result = null;
		//不同datumn下是否宽大处理,其实不同datumn下属于坐标转换范畴了
		boolean lenient = true;
		try {
			
			CoordinateReferenceSystem sourceCRS = CRS.decode("epsg:"+String.valueOf(epsgSource));
			CoordinateReferenceSystem targetCRS = CRS.decode("epsg:"+String.valueOf(epsgTarget));
			//当转换的两种坐标系的datum不同，会报错Bursa-Wolf parameters
			//MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS);
			MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, lenient);
			
			result= JTS.transform(geom, transform);
		} catch (MismatchedDimensionException 
				| TransformException 
				| FactoryException e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	/**
	 * 投影转换-wkt
	 * 
	 * @param geom
	 * @param wktSource
	 * @param wktTarget
	 * @return
	 */
	public static Geometry geomPrjTransform2(Geometry geom, String wktSource, String wktTarget){
		Geometry result = null;
		//不同datumn下是否宽大处理,其实不同datumn下属于坐标转换范畴了
		boolean lenient = true;
		try {
			CoordinateReferenceSystem sourceCRS = CRS.parseWKT(wktSource);
			CoordinateReferenceSystem targetCRS = CRS.parseWKT(wktTarget);
			//当转换的两种坐标系的datum不同，会报错Bursa-Wolf parameters
			//MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS);
			MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, lenient);
			
			result= JTS.transform(geom, transform);
		} catch (MismatchedDimensionException 
				| TransformException 
				| FactoryException e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	/**
	 * getBlockJzdList 获取一个gpkg文件中所有图形要素的界址点坐标串
	 * 
	 * 界址点内包含：界址点号,环（岛宗）标记,x,y。同时界址点间采用";"分割。即J1,1,x1,y1; J2,1,x2,y2; 。。。Jn,2,xn,yn;
	 * 
	 * @param gpkgPath  
	 * @return 
	 */
	public static Map<String,List<String>> getBlockJzdList(String gpkgPath){
		Map<String,List<String>> results = new HashMap<String,List<String>>();
		// geoPackage
		File existingGeoPackage = new File(gpkgPath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);

		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(0);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			
			FeatureResultSet cursor = featureDao.queryForAll();
			//FeatureResultSet cursor = featureDao.queryForEq(gpkg_uuid, new ColumnValue(uuidValue));
			int resCount = cursor.getCount();
			List<String> uuidJzdlist = new ArrayList<String>();
			int i=0;
			while (cursor.moveToNext()) {
				i++;
				String feaIndex= String.format("%d", i);
				
				FeatureRow featureRow = cursor.getRow();
				//一个要素可能包含多个图形对象（地块）
				Map<String,String> jzdlist = gpkgFea2Jzdlist(featureRow);
				
				Set<String> keySet = jzdlist.keySet();
				Iterator<String> keyIter = keySet.iterator();
				while(keyIter.hasNext()) {
					String key = keyIter.next();
					String jzdstr = jzdlist.get(key);
					
					uuidJzdlist.add(jzdstr);
				}
				
				results.put(feaIndex, uuidJzdlist);
			}
			
			cursor.close();
		}
		
		return results;
	}
	public static Map<String,List<String>> getBlockJzdList(String gpkgPath,String tableName){
		Map<String,List<String>> results = new HashMap<String,List<String>>();
		// geoPackage
		File existingGeoPackage = new File(gpkgPath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);

		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			//String tableName = feaTables.get(0);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			
			FeatureResultSet cursor = featureDao.queryForAll();
			//FeatureResultSet cursor = featureDao.queryForEq(gpkg_uuid, new ColumnValue(uuidValue));
			int resCount = cursor.getCount();
			List<String> uuidJzdlist = new ArrayList<String>();
			int i=0;
			while (cursor.moveToNext()) {
				i++;
				String feaIndex= String.format("%d", i);
				
				FeatureRow featureRow = cursor.getRow();
				//一个要素可能包含多个图形对象（地块）
				Map<String,String> jzdlist = gpkgFea2Jzdlist(featureRow);
				
				Set<String> keySet = jzdlist.keySet();
				Iterator<String> keyIter = keySet.iterator();
				while(keyIter.hasNext()) {
					String key = keyIter.next();
					String jzdstr = jzdlist.get(key);
					
					uuidJzdlist.add(jzdstr);
				}
				
				results.put(feaIndex, uuidJzdlist);
			}
			
			cursor.close();
		}
		
		return results;
	}
	public static Map<String,List<String>> getBlockJzdList(String gpkgPath,int tableIndex){
		Map<String,List<String>> results = new HashMap<String,List<String>>();
		// geoPackage
		File existingGeoPackage = new File(gpkgPath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);

		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(tableIndex);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			
			FeatureResultSet cursor = featureDao.queryForAll();
			//FeatureResultSet cursor = featureDao.queryForEq(gpkg_uuid, new ColumnValue(uuidValue));
			int resCount = cursor.getCount();
			List<String> uuidJzdlist = new ArrayList<String>();
			int i=0;
			while (cursor.moveToNext()) {
				i++;
				String feaIndex= String.format("%d", i);
				
				FeatureRow featureRow = cursor.getRow();
				//一个要素可能包含多个图形对象（地块）
				Map<String,String> jzdlist = gpkgFea2Jzdlist(featureRow);
				
				Set<String> keySet = jzdlist.keySet();
				Iterator<String> keyIter = keySet.iterator();
				while(keyIter.hasNext()) {
					String key = keyIter.next();
					String jzdstr = jzdlist.get(key);
					
					uuidJzdlist.add(jzdstr);
				}
				
				results.put(feaIndex, uuidJzdlist);
			}
			
			cursor.close();
		}
		
		return results;
	}

	/**
	 * 获取一个gpkg文件中制定UUID集合的图形要素的界址点坐标串
	 * 
	 * 界址点内包含：界址点号,环（岛宗）标记,x,y。同时界址点间采用";"分割。即J1,1,x1,y1; J2,1,x2,y2; 。。。Jn,2,xn,yn;
	 * 
	 * @param gpkgPath
	 * @param uuidSet 
	 * @return
	 */
	public static Map<String,List<String>> getBlockJzdListByUUIDSet(String gpkgPath, Set<String> uuidSet){
		Map<String,List<String>> results = new HashMap<String,List<String>>();
		// geoPackage
		File existingGeoPackage = new File(gpkgPath);
		GeoPackage geoPackage = GeoPackageManager.open(existingGeoPackage);

		List<String> feaTables = geoPackage.getFeatureTables();
		if (feaTables.size() > 0) {
			// 默认只处理第一个表
			String tableName = feaTables.get(0);
			FeatureDao featureDao = geoPackage.getFeatureDao(tableName);
			
			for (String uuidValue : uuidSet) {
				FeatureResultSet cursor = featureDao.queryForEq(gpkg_uuid, new ColumnValue(uuidValue));
				int resCount = cursor.getCount();
				System.out.println();
				System.out.println(String.format("--->uuid: %s, count: %d  ", uuidValue, resCount));

				List<String> uuidJzdlist = new ArrayList<String>();
				while (cursor.moveToNext()) {
					FeatureRow featureRow = cursor.getRow();
					//一个要素可能包含多个图形对象（地块）
					Map<String,String> jzdlist = gpkgFea2Jzdlist(featureRow);
					
					Set<String> keySet = jzdlist.keySet();
					Iterator<String> keyIter = keySet.iterator();
					while(keyIter.hasNext()) {
						String key = keyIter.next();
						String jzdstr = jzdlist.get(key);
						
						uuidJzdlist.add(jzdstr);
					}
				}
				
				cursor.close();
				
				results.put(uuidValue, uuidJzdlist);
			}
		}
		
		return results;
	}


}
